Podobnie jak rzeczywiste zombie, proces zombie nie może zostać zabity, ponieważ jest już martwy.
Jak to sie dzieje
Gdy w systemie Linux / Unix proces umiera / kończy się, wszystkie informacje z procesu są usuwane z pamięci systemowej, pozostaje tylko deskryptor procesu. Proces przechodzi w stan Z (zombie). Jego proces nadrzędny otrzymuje sygnał z jądra: SIGCHLD
oznacza to, że jeden z jego procesów potomnych kończy działanie, zostaje przerwany lub wznowiony po przerwaniu (w naszym przypadku po prostu wychodzi).
Proces nadrzędny musi teraz wykonać wait()
wywołanie systemowe, aby odczytać status wyjścia i inne informacje z procesu potomnego. Następnie deskryptor zostaje usunięty z pamięci, a proces nie jest już zombie.
Jeśli proces nadrzędny nigdy nie wywołuje wywołania wait()
systemowego, deskryptor procesu zombie pozostaje w pamięci i zjada mózg. Zwykle nie widzisz procesów zombie, ponieważ powyższa procedura zajmuje mniej czasu.
Świt umarłych
Każdy deskryptor procesu potrzebuje bardzo małej ilości pamięci, więc kilka zombie nie jest bardzo niebezpiecznych (jak w prawdziwym życiu). Jednym z problemów jest to, że każdy proces zombie zachowuje swój identyfikator procesu, a system operacyjny Linux / Unix ma ograniczoną liczbę pid. Jeśli niepoprawnie zaprogramowane oprogramowanie generuje wiele procesów zombie, może się zdarzyć, że procesów nie można już uruchomić, ponieważ nie ma już dostępnych identyfikatorów procesów.
Tak więc, jeśli są w dużych grupach, są bardzo niebezpieczni (jak w wielu filmach pokazano bardzo dobrze)
Jak możemy się bronić przed hordą zombie?
Strzał w głowę działałby, ale nie znam tego polecenia (SIGKILL nie zadziała, ponieważ proces jest już martwy).
Cóż, możesz wysłać SIGCHLD przez kill do procesu nadrzędnego, ale kiedy ignoruje ten sygnał, co wtedy? Jedyną opcją jest zabicie procesu nadrzędnego, a proces inicjacji „adoptuje” zombie. Init okresowo dzwoni do wait()
syscall, aby oczyścić swoje dzieci zombie.
W Twoim przypadku
W twoim przypadku musisz wysłać SIGCHLD do procesu crond:
root@host:~# strace -p $(pgrep cron)
Process 1180 attached - interrupt to quit
Następnie z innego terminala:
root@host:~$ kill -17 $(pgrep cron)
Dane wyjściowe to:
restart_syscall(<... resuming interrupted call ...>) = ? ERESTART_RESTARTBLOCK (To be restarted)
--- SIGCHLD (Child exited) @ 0 (0) ---
wait4(-1, 0x7fff51be39dc, WNOHANG, NULL) = -1 ECHILD (No child processes) <-- Here it happens
rt_sigreturn(0xffffffffffffffff) = -1 EINTR (Interrupted system call)
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=1892, ...}) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {0x403170, [CHLD], SA_RESTORER|SA_RESTART, 0x7fd6a7e9d4a0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({42, 0}, ^C <unfinished ...>
Process 1180 detached
Widzisz, że wait4()
syscall zwraca -1 ECHILD, co oznacza, że nie istnieje żaden proces potomny. Wniosek jest następujący: cron reaguje na wywołanie systemowe SIGCHLD i nie powinien wymuszać apokalipsy.