LINUX.ORG.RU

Почему ядро не может высвободить ресурсы?

 ,


0

1

Есть подвисания программ, которые нельзя убить

kill -9 some

Они остаются зависшими. В процессах сидят как

defunc some

При этом вся система нормально функционирует. И с этим defunс система может работать неграниченное кол-во времени

Вопрос! Почему ядро не может высвободить ресурсы в userspace(ring3) программы? Я понимаю, если бы сама программа была связана с какими-то датчиками внешними, которые не отвечают и ядро внутри себя в каких-то драйверах повесилось, но тут какая-то хреновина консольная, которая вообще ни с чем не связана и она становится зомби. Но(!) даже если связана, это что, нельзя корректно обработать? Я считаю, что это бага, которая уже лет 30 живет в ядре

Вот вчера завис ff, не убивался. Иксы перезапустить невозможно. Ребутаться не хочет. Вопрос решается только кнопкой reset. Windows95 воочию!

★★★

Последнее исправление: serg002 (всего исправлений: 2)

Это называется «баг в ДНК». Сам принцип организации работы с процессами в Линукс не позволяет избавиться от зомби. Считается что в правильно работающей системе их не должно существовать, и раз они есть нужно решать причину их появления, а не бороться с последствиями. Чтобы убивать зомби нужна какая то более другая программная архитектура работы с процессами, не наследующая UNIX. И если её сделать это будет уже не Линукс, а какая то другая ОС с другим ядром. И это потащит за собой редизайн вообще всего ПО и утрату совместимости.

это бага, которая уже лет 30 живет в ядре

И до этого жила в любом UNIX. И сейчас живёт в его потомках. NOTABUG WONTFIX

Но мне кажется ты и сам прекрасно всё это знаешь и просто пришёл об этом поговорить.

Jameson ★★★★★
()
Последнее исправление: Jameson (всего исправлений: 6)
Ответ на: комментарий от Jameson

И всё-таки непонятно. Ядро знает, что процесс зомби (ведь обозначает его), знает (или именно здесь я ошибаюсь?) где для него выделена память - что мешает его убрать?

token_polyak ★★★★★
()
Последнее исправление: token_polyak (всего исправлений: 1)
Ответ на: комментарий от token_polyak

Я не настоящий сварщик, но смутно помню что если родитель помер раньше сыночка и сыночек осиротел его усыновляет init (1) и гуманно того этого... А вот если он его усыновить не может — значит что то разрушено в его таблицах, ядро «изолирует» этот процесс делая его «зомби». Суть в том что это и есть защитная реакция на нештатную ситуацию и попытка спасти остальное, а именно init (1) от повреждения стрёмным неуправляемым процессом. Потому что рухнет init — рухнет всё.

Jameson ★★★★★
()
Последнее исправление: Jameson (всего исправлений: 1)
Ответ на: комментарий от Jameson

Ctrl+alt+del

firefox(процесс не отвечает)

снять процесс!!!

процесс не может быть снят(процесс завис или не отвечает)

Всегда ваша, надстройка над Dos, windows95

serg002 ★★★
() автор топика
Ответ на: комментарий от Jameson

Считается что в правильно работающей системе их не должно существовать

Вообще конечно это ахтунг. Такой же ахтунг, как был 12309. Который был, но все его отрицали. Прикрывать баги идеологией - это конечно хорошо, но по факту имеется программа, которую не перезапустить из-за того, что ее дубликат невозможно убить. И решить вопрос можно только ребутом(как в windows95)

А так-то да, если следовать идеологии, тогда зачем вообще зомби? Всё же должно по идеологии работать и такие процессы вообще не должны быть в природе. А? Попытка спасти всё остальное? Т.е вопреки идеологии какие-то действия пытаются произвести. А зачем? Есть же идеология. Или может она неправильная? М? Та не! глупости какие!

serg002 ★★★
() автор топика
Последнее исправление: serg002 (всего исправлений: 2)
Ответ на: комментарий от serg002

12309 не отрицали. Просто он был «подземным стуком в подвале» на который жаловались «уважаемым учоным». Его было крайне трудно локализовать, по разным причинам, я не буду тут цитировать всю историю охоты на него.

Jameson ★★★★★
()
Ответ на: комментарий от serg002

Да говно Линукс, говно, я согласен. И UNIX, который он пародирует, древний окаменелый кусок говна. Есть более перспективные архитектуры и их концепции, непонятно только что ты тут забыл. Хотя может ты можешь в LKML что нибудь предложить по этому поводу, просто пока не готов? Предложение «прекратить вот это всё и разойтись» не считается.

Jameson ★★★★★
()
Последнее исправление: Jameson (всего исправлений: 2)
Ответ на: комментарий от Jameson

Давай не будем играть в идиотиков. В планировщике CFQ была бага, которая приводила к этому всему. При переключении на deadline и тюнинг оного - убирал проблему(или переключение на BFQ, который не хотели принимать в ядро). А потом появился NCQ на дисковых устройствах и 12309 резко пропала. Прям детектив, ага

serg002 ★★★
() автор топика
Ответ на: комментарий от Jameson

Хотя может ты можешь в LKML что нибудь предложить по этому поводу, просто пока не готов?

Это не аргумент. Почему человек, который говорит на обувь, что они плохие - обязательно должен разобраться с обувной индустрией и начать делать хорошие сапоги?

serg002 ★★★
() автор топика
Ответ на: комментарий от serg002

Просто непонятно какой реакции этот человек ждёт. Ну плохая обувь, да, все согласны, эта обувь плохая. Дальше что? Твои действия, действия окружающих, кто это слышит и об этом и так знает, какие? Без «переписать ядро в более другое ядро» это не решается, и даже есть альтернативные ОС с другими архитектурами. Ну так иди в LKML, раскрой глаза там всем, сообщи что король то голый и архитектура говно. И всё, все всё поймут и разойдутся.

Jameson ★★★★★
()

Вот вчера завис ff, не убивался. Иксы перезапустить невозможно.

Что значит «завис ff», он стал defunct? Так это иксы заглючили, а не ff.

thesis ★★★★★
()
Ответ на: комментарий от serg002

Ага, во всём были виноваты масоны, которые скрывали, врали и защищали сломанный планировщик. Могли бы сразу поправить, ведь им, масонам, сразу всё было известно и понятно про 12309, возможно что это именно они, масоны, сами и нассали в кран испортили CFQ, из присущей им вредности. И из неё же, из вредности, потом не чинили. Починилось само, Божьим вмешательством в развитие технологий, масоны очень от этого грустят. И с зомби так же, могут ведь что то сделать, но тридцать лет отрицают существование проблемы и врут, всем врут и скрывают что могут легко всё исправить. Из вредности опять таки.

Зачем я вообще с тобой в дискуссии вступаю? Всё, я кончил.

Jameson ★★★★★
()
Последнее исправление: Jameson (всего исправлений: 2)

Почему ядро не может высвободить ресурсы в userspace(ring3) программы?

Оно может и высвободило. Зомби это не процесс, это запись о статусе завершения.

ya-betmen ★★★★★
()
Ответ на: комментарий от ya-betmen

Оно может и высвободило. Зомби это не процесс, это запись о статусе завершения.

А может и нет, но ЕМНИП занимаемая зомбаком память может быть вытеснена в своп. Зомби это не совсем запись о статусе завершения, это запись о том что завершить процесс штатно не удалось и коммуникация с ним невозможна. Но не берусь утверждать что истину глаголю, может сейчас уже как то по другому. Я в прошлом веке в теорию этого всего вникал.

Jameson ★★★★★
()
Последнее исправление: Jameson (всего исправлений: 1)
Ответ на: комментарий от Jameson

Ты это серьёзно? Я думал это любой не-нуб знает.

Если процесс завершается то родитель может собрать код его завершения через wait(). Этот системный вызов привязан к pid процесса-потомка, соответственно pid остаётся занят до тех пор, пока родитель не скажет что ему эта запись больше не нужна. Память там разумеется никакая не выделена уже, и процесса нет. Это просто занятый слот чтобы вернуть его в wait() родителю.

завершить процесс штатно не удалось

Нет, это полностью штатное завершение как раз, только родитель не сразу отреагировал (или в родителе баг и он не собирает эти данные).

Если родителю эти данные не нужны, то он должен сделать signal(SIGCHLD, SIG_IGN) и тогда слоты его потомков будут освобождаться сразу (но и wait() на уже завершившегося потомка он тогда сделать не сможет).

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

Нет, я не серьёзно, я не системный программист, вообще не программист и на C не пишу. Но ты наверное можешь дать расклад почему получаются зомби и почему от них без перезагрузки не избавиться. Я без издёвок, это заполнит позорный пробел в моих знаниях. И заодно возможно объяснит TC почему невозможность «убить» зомби это не тридцатилетний «заговор молчания и игнора», а архитектурная неизбежность.

Jameson ★★★★★
()
Ответ на: комментарий от Jameson

Я расписал же выше. Без перезагрузки избавиться элементарно - убить родителя или исправить баг в нём.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Я писал до того как ты пост дополнил. А если родитель уже того этого, помер деток осиротив, им становится init? Убить init не вариант и остаётся только баг в родителе исправлять, чтобы он не помирал внезапно? Я смутно помню что «сирот» инит усыновляет и усыпляет, и «зомби» это когда он этого сделать по каким то причинам не может. По каким?

Jameson ★★★★★
()
Ответ на: комментарий от Jameson

init исправно чистит своих зомби-детей. Хотя от systemd всякого можно ожидать, но думаю даже там такого нет.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Вот мне помнится что тут не юзерспейсные дела и от того кто у нас инит, systemd, что то из openrc или вообще /bin/sh, это не зависит. Это дело ядра и процесс номер один просто формально родителем назначается, чтобы ему сигнал послать. И зомби возникнет при любом инит если процесс все сигналы проигнорирует. Всмысле не «init чистит», чистит ядро.

Jameson ★★★★★
()
Последнее исправление: Jameson (всего исправлений: 1)
Ответ на: комментарий от Jameson

Ядро всё уже почистило, иначе он бы не был зомби. Почему запись залипает - вопрос другой, тут широкое поле для разного рода багов.

ya-betmen ★★★★★
()
Ответ на: комментарий от ya-betmen

Вот этот «другой вопрос» и интересен, ТС предполагает что это либо заговор молчания и игнора проблемы (разбираться и чинить не хотят), либо тщательно скрываемое слабоумие разработчиков (разобраться и починить не могут). Я вот помню что это что то архитектурное и не решаемое в принципе, но объяснить это словами не могу, как собачка, которая всё понимает, но сказать не может. Ты вот кажется можешь, расскажи, интересно же.

Jameson ★★★★★
()
Ответ на: комментарий от Jameson

Зомби появляется при одновременном выполнении следующих условий (и только так, никак иначе):

1) процесс завершился

2) у его родителя не стоит SIG_IGN на SIGCHLD

3) его родитель в данный момент не висит в сисколле wait() или его аналоге, пригодном для забирания данных о завершившемся процессе

Зомби исчезает в двух случаях:

1) родитель зомби-процесса (в том числе init, если родитель - он) вызвал wait(), пригодный для забирания данных о завершившемся процессе

2) [тут не уверен, но по идее должно быть так] родитель зомби-процесса завершился, а у процесса с pid1 стоит игнорирование SIGCHLD

Соответственно, если init не бажный, то он либо ставит SIG_IGN на SIGCHLD, либо регулярно собирает коды завершения с помощью wait(). Наличие у него зомби-потомков при этом исключено.

firkax ★★★★★
()
Ответ на: комментарий от Jameson

У автора wm или кто там запустил фф - не забрал от него код. init ни при чём.

firkax ★★★★★
()
Ответ на: комментарий от Jameson

Я вот помню что это что то архитектурное и не решаемое в принципе

Да, запись ждет когда её удалят, если этого никто делать не хочет она будет висеть. Так и задумано.

ya-betmen ★★★★★
()
Ответ на: комментарий от firkax

элементарно убить родителя

И родитель и чилды - defunc

или исправить баг в нём

Почему ядро не может просто убить родителя и чилдов и освободить ресурсы. Что ему это мешает сделать?

serg002 ★★★
() автор топика
Ответ на: комментарий от ya-betmen

Да, запись ждет когда её удалят, если этого никто делать не хочет она будет висеть. Так и задумано.

Я правильно понимаю что убийство init таблицу почистит, но с точки зрения оператора это эквивалентно перезагрузке? И именно что невозможность перезапуска init с сохранением всего остального и есть нерешаемая архитектурная проблема, так как для её решения нужно переделать вообще всю концепцию управления процессами?

Jameson ★★★★★
()
Ответ на: комментарий от Jameson

Я правильно понимаю что убийство init таблицу почистит

Где ты видел зомбей с parent = init?

firkax ★★★★★
()
Ответ на: комментарий от serg002

Родитель defunc процесса - bash, и команда была с & ? Значит в скрипте должна стоять команда wait где-то. Или если не хочешь ставить wait - запускай этот подпросесс из сабщелла, так:

( command & )
firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от serg002

Вот с этого надо было начинать. Осталось только увидеть сам скрипт и список процессов с непонятными статусами.

shell-script ★★★★★
()
Ответ на: комментарий от shell-script

http://paste.debian.net/hidden/0279d47f/ я думаю, что запускалка никакого отношения к неубиваемому ff не имеет. Потому как точно такая же трабла имеется, скажем, у deluged

serg002 ★★★
() автор топика
Последнее исправление: serg002 (всего исправлений: 4)
Ответ на: комментарий от firkax

Но сейчас нет же defunc. Это бывает раз в две-три недели. Из-под скрипта запуск выглядит так: ps axo user,pid,ppid,command |grep firefox

root       17435    2103 sudo -u user bash -c  firefox-bin  >/dev/null 2>&1
user       17436   17435 bash -c  firefox-bin  >/dev/null 2>&1
user       17437   17436 /opt/firefox/firefox-bin
user       17590   17437 /opt/firefox/firefox-bin -contentproc -childID 1 -isForBrowser -prefsLen 1 -prefMapSize 251718 -jsInitLen 277748 -parentBuildID 20220330194208 -appDir /opt/firefox/browser 17437 true tab
user       17878   17437 /opt/firefox/firefox-bin -contentproc -childID 6 -isForBrowser -prefsLen 4567 -prefMapSize 251718 -jsInitLen 277748 -parentBuildID 20220330194208 -appDir /opt/firefox/browser 17437 true tab
user       17934   17437 /opt/firefox/firefox-bin -contentproc -childID 7 -isForBrowser -prefsLen 4567 -prefMapSize 251718 -jsInitLen 277748 -parentBuildID 20220330194208 -appDir /opt/firefox/browser 17437 true tab
user       18592   17437 /opt/firefox/firefox-bin -contentproc -childID 11 -isForBrowser -prefsLen 5268 -prefMapSize 251718 -jsInitLen 277748 -parentBuildID 20220330194208 -appDir /opt/firefox/browser 17437 true tab
user       19385   17437 /opt/firefox/firefox-bin -contentproc -parentBuildID 20220330194208 -prefsLen 5315 -prefMapSize 251718 -appDir /opt/firefox/browser 17437 true rdd
user      587345   17437 /opt/firefox/firefox-bin -contentproc -childID 126 -isForBrowser -prefsLen 8150 -prefMapSize 251718 -jsInitLen 277748 -parentBuildID 20220330194208 -appDir /opt/firefox/browser 17437 true tab
user      693861   17437 /opt/firefox/firefox-bin -contentproc -childID 133 -isForBrowser -prefsLen 8150 -prefMapSize 251718 -jsInitLen 277748 -parentBuildID 20220330194208 -appDir /opt/firefox/browser 17437 true tab
user      694907   17437 /opt/firefox/firefox-bin -contentproc -childID 134 -isForBrowser -prefsLen 8150 -prefMapSize 251718 -jsInitLen 277748 -parentBuildID 20220330194208 -appDir /opt/firefox/browser 17437 true tab
user      694916   17437 /opt/firefox/firefox-bin -contentproc -childID 135 -isForBrowser -prefsLen 8150 -prefMapSize 251718 -jsInitLen 277748 -parentBuildID 20220330194208 -appDir /opt/firefox/browser 17437 true tab
user      699040  656621 grep --color=always --no-messages firefox
serg002 ★★★
() автор топика
Последнее исправление: serg002 (всего исправлений: 1)
Ответ на: комментарий от firkax

Если мастер-процесс фф живой а defunc его потомки - то баг в фф.

Может и баг, но вернуть опять к истоку: почему такой случай не может обработать ядро. Почему я должен перезагружать тачку, чтобы пофиксить это. Почему /-9/ - не жесткий килл всего, что в юзерспейсе захавало ресурсы и сдохло

Именно поэтому всякие Erlang делают свои менеджеры процессов. Потому что ядро не в состоянии покилять юзерспейс корректно. А Erlang может

serg002 ★★★
() автор топика
Последнее исправление: serg002 (всего исправлений: 2)
Ответ на: комментарий от Jameson

но смутно помню

Нет, неправильно ты помнишь.

Чтобы понять, что такое зомби, нужно вспомнить, что юникс тесно связан с C, а в C main - это функция, объявляемая вот так:

int main(int argc, char * argv[])

Здесь важно, что main возвращает целочисленное значение. Это ровно то значение, которое в шеле видно. Вот простой пример:

#include <stdlib.h>

int main(int argc, char * argv[])
{
  return 42;
}

потом

~ ❯ c99 -Wall lor.c -o lor
~ ❯ ./lor
[42] ~ ❯ echo $?
42
~ ❯

(отдельно есть exit(), но это сейчас не важно).

Раз main() возвращает значение, это значение можно поймать, аналогично тому, как это делает шел:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char * argv[])
{
  pid_t child_pid;
  pid_t wait_pid;
  int child_err;

  child_pid = fork();
  if (child_pid == 0) {
    printf("I am a child with PID %d and I am sleeping\n", getpid());
    sleep(1);
    printf("I am awake\n");
    return 42;
  }
  else
  {
    printf("I am a parent waiting for child with PID %d\n", child_pid);
    wait_pid = wait(&child_err);
    printf("I got error %d from child %d\n", WEXITSTATUS(child_err), wait_pid);
    return 0;
  }
}

Тогда

~ ❯ c99 -Wall wait-lor.c -o wait-lor
~ ❯ ./wait-lor
I am a parent waiting for child with PID 383
I am a child with PID 383 and I am sleeping
I am awake
I got error 42 from child 383
~ ❯

Тут видно, что системный вызов wait() ждёт возврата ребёнка и получает код возврата в child_err, а потом его печатает.

Однако, если ребёнка никто не ждёт, а main() в нём уже закончился, то код возврата девать некуда и он остаётся в таблицах до тех пор, пока его кто-то не подберёт. Вот тут пример родителя, пренебрегающего родительскими обязанностями:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char * argv[])
{
  pid_t child_pid;

  child_pid = fork();
  if (child_pid == 0) {
    printf("I am a child with PID %d and I am sleeping\n", getpid());
    sleep(1);
    printf("I am awake\n");
    return 42;
  }
  else
  {
    printf("I am a parent and I give up, parenting is too hard!\n");
    sleep(10);
    return 0;
  }
}

Здесь родитель спит, а ребёнок умер (трагедия). Поэтому ребенок превращается в зомби. Потом родитель тоже умирает, в этот момент ребёнка подбирает init, получает код возврата и чистит таблицу зомби. Это быстро просиходит, поэтому второй шаг не виден.

~ ❯ c99 dont-wait-lor.c -o dont
~ ❯ ./dont
I am a parent and I give up, parenting is too hard!
I am a child with PID 413 and I am sleeping
I am awake
^Z
[1]  + 412 suspended  ./dont
[148] ~ ❯ bg
[1]  + 412 continued  ./dont
~ ❯ ps -o pid,user,state,pcpu,vsize,args -HA
  PID USER     S %CPU    VSZ COMMAND
[...]
   32 toor     S  0.0  20748           /bin/zsh
  412 toor     S  0.0  10500             ./dont
  413 toor     Z  0.0      0               [dont] <defunct>
  418 toor     R  0.0  17752             ps -o pid,user,state,pcpu,vsize,args -HA
[...]
~ ❯
[1]  + 412 done       ./dont
~ ❯

Вот тут я запустил dont, он имеет PID 412, порождает ребёнка 413, тот выходит сразу, но родитель в это время спит и вот у нас зомби, что видно в колонке «S».

А вот если он его усыновить не может — значит что то разрушено в его таблицах

В общем, ничего «разрушено в его таблицах» не случается, не надо людей в заблуждение вводить.

ivlad ★★★★★
()

Это ещё что. На чипе Amlogic A311D проблема с памятью, немного попересобирав ядро удалось победить мёртвые зависы, но теперь иногда «невозможно выделить память». Всегда по разному, памяти всегда вагон, а когда кончается всё норм!

burato ★★★★★
()
Ответ на: комментарий от serg002

И родитель и чилды - defunc

Значит лечи парента родителя.

no-dashi-v2 ★★★
()
Ответ на: комментарий от serg002

В баше там цикл бесконечный, который в случае отсутствия в процессах ff - запускает его

Запускай ff форграунде. Тривиально же.

Неудивительно что с таким уровнем ниже плинтуса тебе кажется что все вокруг тебя подсиживают.

no-dashi-v2 ★★★
()
Ответ на: комментарий от serg002

почему такой случай не может обработать ядро.

Может и обработало, иначе бы у тебя зомби не появился.

ya-betmen ★★★★★
()
Ответ на: комментарий от serg002

Ну что ж ты такой упёртый? Тебе уже раз пять наверно сказали, повторю в шестой, попробуй всё-таки понять: зомби-процесс - это слот ожидания для его родителя. Самого процесса и никаких занятых ресурсов (кроме номера pid) там уже нет. Удалить его нельзя - на него всё ещё есть ссылка из родителя, которую тот может захотеть прочитать. Как родитель её освобождает - так этот pid-слот и освобождается до конца. Удалять объект, на который есть ссылки, нельзя - вот это как раз было бы жёстким багом.

firkax ★★★★★
()
Ответ на: комментарий от QsUPt7S

Зачем же так круто? Мб REISUB бы помог…

Upd.: Заинтересовался вопросом, оказалось что REISUB уже не рекомендуется, а рекомендуется SysRq-b, что эквивалентно нажатию кнопки reset…

QsUPt7S ★★
()
Последнее исправление: QsUPt7S (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.