Process

Linux 如何“殺死”一個程序?

  • October 18, 2019

經常讓我感到困惑的是,儘管我從事電腦專業工作已有幾十年,從事 Linux 工作已有十年,但實際上我將作業系統的大部分功能視為一個黑匣子,與魔法沒什麼兩樣。

今天我想到了這個kill命令,雖然我每天多次使用它(無論是在它的“正常”和-9風味中),但我必須承認我完全不知道它在幕後是如何工作的。

從我的角度來看,如果一個正在執行的程序被“掛起”,我呼叫kill它的 PID,然後它突然不再執行了。魔法!

那裡真的發生了什麼?手冊頁談論“信號”,但肯定這只是一個抽象。發送kill -9到程序不需要程序的合作(如處理信號),它只是將其殺死。

  • Linux如何阻止程序繼續佔用CPU時間?
  • 它是否從計劃中刪除?
  • 它是否斷開程序與其打開的文件句柄的連接?
  • 程序的虛擬記憶體是如何釋放的?
  • 記憶體中是否有類似全域表的東西,Linux 保留對程序佔用的所有資源的引用,當我“殺死”一個程序時,Linux 只是簡單地遍歷該表並一一釋放資源?

我真的很想知道這一切!

向程序發送 kill -9 不需要程序的合作(如處理信號),它只是將其殺死。

你假設因為一些信號可以被捕捉和忽略,它們都涉及合作。但根據man 2 signal,“信號SIGKILL 和 SIGSTOP 不能被擷取或忽略”。SIGTERM 可以被擷取,這就是為什麼 plainkill並不總是有效的——通常這意味著程序的處理程序中的某些東西出錯了。1

如果程序沒有(或不能)為給定信號定義處理程序,核心將執行預設操作。 在 SIGTERM 和 SIGKILL 的情況下,這是終止程序(除非它的 PID 為 1;核心不會終止init)2 意味著它的文件句柄被關閉,它的記憶體返回到系統池,它的父程序收到 SIGCHILD,它的孤兒子代由 init 等繼承,就好像它呼叫過一樣exit(參見 參考資料man 2 exit)。該程序不再存在——除非它最終成為殭屍,在這種情況下,它仍然在核心的程序表中列出一些資訊;當其父母不這樣做時會發生這種情況wait並妥善處理這些資訊。但是,殭屍程序不再分配任何記憶體,因此無法繼續執行。

記憶體中是否有類似全域表的東西,Linux 保留對程序佔用的所有資源的引用,當我“殺死”一個程序時,Linux 只是簡單地遍歷該表並一一釋放資源?

我認為這已經足夠準確了。物理記憶體按頁跟踪(一頁通常等於 4 KB 塊),這些頁從全域池中取出並返回到全域池。稍微複雜一點的是,一些已釋放的頁面會被記憶體,以防再次需要它們包含的數據(即從仍然存在的文件中讀取的數據)。

手冊頁談論“信號”,但肯定這只是一個抽象。

當然,所有信號都是抽象的。它們是概念性的,就像“過程”一樣。我在玩語義,但是如果您的意思是 SIGKILL 在質量上與 SIGTERM 不同,那麼是和否。是的,因為它無法被擷取,但不是,因為它們都是信號。以此類推,蘋果不是橙子,但根據先入為主的定義,蘋果和橙子都是水果。SIGKILL 似乎抽象,因為你無法捕捉到它,但它仍然是一個信號。這是一個 SIGTERM 處理的例子,我相信你以前見過這些:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void sighandler (int signum, siginfo_t *info, void *context) {
   fprintf (
       stderr,
       "Received %d from pid %u, uid %u.\n",
       info->si_signo,
       info->si_pid,
       info->si_uid
   );
}

int main (void) {
   struct sigaction sa;
   memset(&sa, 0, sizeof(sa));
   sa.sa_sigaction = sighandler;
   sa.sa_flags = SA_SIGINFO;
   sigaction(SIGTERM, &sa, NULL);
   while (1) sleep(10);
   return 0;
}

這個過程將永遠休眠。您可以在終端中執行它並使用 SIGTERM 發送它kill。它吐出類似的東西:

Received 15 from pid 25331, uid 1066.

1066 是我的 UID。PID 將kill是執行的 shell 的 PID,或者如果你 fork 它,則為 kill 的 PID ( kill 25309 & echo $?)。

同樣,為 SIGKILL 設置處理程序沒有意義,因為它不起作用。3如果我kill -9 25309,該過程將終止。但這仍然是一個信號;核心有關於誰發送了信號,它是什麼類型的信號等資訊。


  1. 如果您還沒有查看可能的信號列表,請參閱kill -l

  2. 另一個例外,正如 Tim Post 下面提到的,適用於不間斷睡眠中的程序。在解決根本問題之前無法喚醒這些信號,因此所有信號(包括 SIGKILL)都會延遲一段時間。然而,一個過程不能故意創造這種情況。

  3. 這並不意味著kill -9在實踐中使用是更好的事情。我的範例處理程序是一個糟糕的處理程序,因為它不會導致exit(). SIGTERM 處理程序的真正目的是讓程序有機會做一些事情,比如清理臨時文件,然後自願退出。如果你使用kill -9,它就沒有這個機會,所以只有在“自願退出”部分似乎失敗時才這樣做。

引用自:https://unix.stackexchange.com/questions/111625