Điều gì xảy ra nếu 'kill -9' không hoạt động?


467

Tôi có một quá trình tôi không thể giết được kill -9 <pid>. Có vấn đề gì trong trường hợp như vậy, đặc biệt là vì tôi là chủ sở hữu của quá trình đó. Tôi nghĩ không có gì có thể trốn tránh killlựa chọn đó .

Câu trả lời:


561

kill -9( SIGKILL ) luôn hoạt động, miễn là bạn có quyền giết quá trình. Về cơ bản, quá trình phải được bắt đầu bởi bạn và không được setuid hoặc setgid, hoặc bạn phải root. Có một ngoại lệ: ngay cả root cũng không thể gửi tín hiệu gây tử vong cho PID 1 ( initquá trình).

Tuy nhiên kill -9không được đảm bảo để làm việc ngay lập tức . Tất cả các tín hiệu, bao gồm SIGKILL, được phân phối không đồng bộ: hạt nhân có thể mất thời gian để phân phối chúng. Thông thường, việc cung cấp tín hiệu mất tối đa vài micro giây, chỉ cần thời gian để mục tiêu có được một lát cắt thời gian. Tuy nhiên, nếu mục tiêu đã chặn tín hiệu , tín hiệu sẽ được xếp hàng cho đến khi mục tiêu mở khóa.

Thông thường, các quy trình không thể chặn SIGKILL. Nhưng mã kernel có thể và các tiến trình thực thi mã kernel khi chúng gọi các cuộc gọi hệ thống . Mã hạt nhân chặn tất cả các tín hiệu khi làm gián đoạn cuộc gọi hệ thống sẽ dẫn đến cấu trúc dữ liệu được hình thành xấu ở đâu đó trong kernel hoặc nói chung là trong một số bất biến kernel bị vi phạm. Vì vậy, nếu (do lỗi hoặc xác định sai) một khối gọi hệ thống vô thời hạn, có thể không có cách nào để giết quá trình. (Nhưng quá trình sẽ bị hủy nếu nó hoàn thành lệnh gọi hệ thống.)

Một quá trình bị chặn trong một cuộc gọi hệ thống là trong giấc ngủ không bị gián đoạn . Lệnh pshoặc topsẽ (trên hầu hết các thông báo) hiển thị nó ở trạng thái D(ban đầu là cho d d isk, tôi nghĩ vậy).

Một trường hợp cổ điển của giấc ngủ dài không thể gián đoạn là các quá trình truy cập các tệp qua NFS khi máy chủ không phản hồi; triển khai hiện đại có xu hướng không áp đặt giấc ngủ không bị gián đoạn (ví dụ: trong Linux, intrtùy chọn gắn kết cho phép tín hiệu làm gián đoạn truy cập tệp NFS).

Đôi khi bạn có thể thấy các mục được đánh dấu Z(hoặc Htrong Linux, tôi không biết phân biệt là gì) trong pshoặc topđầu ra. Đây là những quy trình không phải là quy trình, chúng là các quy trình zombie, không có gì khác hơn là một mục trong bảng quy trình, được giữ xung quanh để quy trình cha mẹ có thể được thông báo về cái chết của con của nó. Họ sẽ biến mất khi quá trình cha mẹ chú ý (hoặc chết).


92
Yor trả lời có vẻ mâu thuẫn. Bạn bắt đầu nói với SIGKILL luôn hoạt động nhưng kết thúc trích dẫn trường hợp ngủ không bị gián đoạn, trong đó SIGKILL có thể không bao giờ hoạt động bên ngoài để tắt kernel. Cũng có hai trường hợp SIGKILL không hoạt động. Với zombie rõ ràng là bạn không thể giết các tiến trình đã chết và với init, do thiết kế đang bỏ qua các tín hiệu SIGKILL.
jlliagre

41
@jlliagre: Giết một zombie không có ý nghĩa gì, nó không còn sống để bắt đầu. Và giết chết một quá trình trong giấc ngủ gián đoạn tác dụng, nó chỉ (như với các tín hiệu khác) không đồng bộ. Tôi đã cố gắng làm rõ điều này trong bản chỉnh sửa của mình.
Gilles

3
Tôi đã viết quá nhiều việc giết một con zombie không có ý nghĩa gì nhưng điều đó không ngăn cản nhiều người thử nó và phàn nàn. Giết một quá trình trong giấc ngủ gián đoạn thực sự hoạt động theo thiết kế, nhưng tôi đã nói về việc giết chết một quá trình trong giấc ngủ không bị gián đoạn có thể thất bại nếu cuộc gọi hệ thống không bao giờ thức dậy.
jlliagre

11
man 5 nfs: " Tùy chọn intr/ nointrmount không được dùng sau kernel 2.6.25. Chỉ SIGKILL mới có thể làm gián đoạn hoạt động NFS đang chờ xử lý trên các kernel này và nếu được chỉ định, tùy chọn mount này sẽ bị bỏ qua để cung cấp khả năng tương thích ngược với các kernel cũ hơn."
Martin Schröder

4
@ imz - IvanZakharyaschev Không phải tôi biết (nhưng tôi có thể không biết). Với sshfs, như là phương sách cuối cùng, bạn có thể giết sshfstiến trình (và tương tự với bất kỳ hệ thống tệp FUSE nào khác: bạn luôn có thể buộc ngắt kết nối theo cách này).
Gilles

100

Đôi khi quá trình tồn tại và không thể bị giết do:

  • là thây ma Tức là quá trình cha mẹ không đọc trạng thái thoát. Quá trình này không tiêu thụ bất kỳ tài nguyên nào ngoại trừ mục nhập PID. Trong topđó có tín hiệu Z
  • giấc ngủ không bị gián đoạn. Điều đó không nên xảy ra nhưng với sự kết hợp của mã hạt nhân lỗi và / hoặc phần cứng lỗi đôi khi nó xảy ra. Phương pháp duy nhất là khởi động lại hoặc chờ đợi. Trong topđó có tín hiệu của D.

2
Zombie không tiêu thụ tài nguyên?
Luc M

7
@Luc M: AFAIK không (ít nhất là trên Linux) - ngoại trừ mục nhập trong bảng quy trình (ví dụ: PID cùng với thông tin như chủ sở hữu, trạng thái thoát, v.v.). Nó chỉ là quá trình chờ đợi sự thừa nhận từ một phần mà nó chấm dứt.
Maciej Piechotka

18
@xenoterracide: Cuối cùng thì có nhưng nếu quá trình cha mẹ vẫn còn tồn tại (ví dụ đó là phiên gnome hoặc thứ gì đó có đầy đủ vai trò tương tự), bạn vẫn có thể có zombie. Về mặt kỹ thuật, công việc của cha mẹ là dọn dẹp nhưng nếu zombie bị mồ côi dọn dẹp sau đó (thuật ngữ là lý do tại sao các lớp unix được thực hiện với cánh cửa đóng kín - bất cứ ai nghe về trẻ mồ côi, thây ma và giết trong một câu có thể có ấn tượng sai).
Maciej Piechotka

5
"... phương pháp duy nhất là khởi động lại hoặc chờ đợi." Đợi bao lâu? Năm tháng đã trôi qua và thây ma của tôi vẫn còn đó.
DarenW

3
@DarenW cho đến khi cha mẹ thừa nhận cái chết của trẻ em. Để biết chi tiết xin vui lòng hỏi tác giả của chương trình.
Maciej Piechotka

32

Có vẻ như bạn có thể có một quá trình zombie . Điều này là vô hại: tài nguyên duy nhất mà quá trình zombie tiêu thụ là một mục trong bảng quy trình. Nó sẽ biến mất khi quá trình cha mẹ chết hoặc phản ứng với cái chết của con nó.

Bạn có thể xem liệu quá trình là một zombie bằng cách sử dụng tophoặc lệnh sau:

ps aux | awk '$8=="Z" {print $2}'

13
Umm, tôi luôn không thích loại tên trường "cứng" này ps. Ai có thể chắc chắn rằng trường bắt buộc sẽ luôn là số 8, với tất cả các triển khai pstrong tất cả các Thông báo?
cú pháp 7/2/2015

26

Kiểm tra của bạn /var/log/kern.log/var/log/dmesg(hoặc tương đương) cho bất kỳ manh mối. Theo kinh nghiệm của tôi, điều này chỉ xảy ra với tôi khi kết nối mạng của NFS đột ngột bị rớt hoặc trình điều khiển thiết bị bị hỏng. Tôi có thể xảy ra nếu một ổ cứng bị hỏng.

Bạn có thể sử dụng lsofđể xem các tập tin thiết bị mà quá trình đã mở.


6
+1 để đề cập đến NFS. Vài năm trước, điều này đã xảy ra với tôi vài tháng một lần - nếu máy chủ NFS gặp sự cố, các máy khách NFS trên tất cả các hộp RHEL (đã vá) sẽ bị treo. kill -9thường không hoạt động, thậm chí sau khi chờ 60 phút. Giải pháp duy nhất là khởi động lại.
Stefan Lasiewski

17

Nếu câu trả lời của @ Maciej và @ Gilles không giải quyết được vấn đề của bạn và bạn không nhận ra quy trình (và hỏi nó là gì với bản phân phối của bạn thì không có câu trả lời). Kiểm tra Rootkit và bất kỳ dấu hiệu nào khác mà bạn đã sở hữu . Một rootkit có nhiều khả năng ngăn bạn giết quá trình. Trong thực tế, nhiều người có khả năng ngăn bạn nhìn thấy chúng. Nhưng nếu họ quên sửa đổi 1 chương trình nhỏ, họ có thể bị phát hiện (ví dụ họ đã sửa đổi top, nhưng không sửa đổi htop). Nhiều khả năng đây không phải là trường hợp nhưng an toàn tốt hơn là xin lỗi.


Tôi đoán nhiều rootkit tự chèn vào kernel để làm cho mọi thứ đơn giản hơn (không cần đoán người dùng có gì và tải xuống MB của các chương trình được vá). Tuy nhiên nó vẫn đáng để kiểm tra (++ phiếu).
Maciej Piechotka

11

Kill thực sự có nghĩa là gửi tín hiệu. có nhiều tín hiệu bạn có thể gửi. giết -9 là một tín hiệu đặc biệt.

Khi gửi tín hiệu ứng dụng xử lý nó. nếu không phải là hạt nhân đối phó với nó. để bạn có thể bẫy tín hiệu trong ứng dụng của bạn.

Nhưng tôi đã nói kill -9 thật đặc biệt. Điều đặc biệt là ứng dụng không nhận được nó. nó đi thẳng vào kernel mà sau đó thực sự giết chết ứng dụng ở cơ hội đầu tiên có thể. nói cách khác giết chết nó

kill -15 gửi tín hiệu SIGTERM, viết tắt của TÍN HIỆU TÍN HIỆU nói cách khác nói cho ứng dụng thoát. Đây là cách thân thiện để nói với một ứng dụng đã đến lúc tắt máy. nhưng nếu ứng dụng không phản hồi kill -9 sẽ giết nó.

nếu kill -9 không hoạt động thì có lẽ điều đó có nghĩa là kernel của bạn đã hết. khởi động lại theo thứ tự. Tôi không thể nhớ điều đó đã từng xảy ra.


5
15 là SIGTERM (giết thân thiện), không phải SIGHUP. SIGHUP dành cho thiết bị đầu cuối điều khiển bị đóng hoặc kênh liên lạc bị mất
JoelFan

11

Đầu tiên, hãy kiểm tra xem đó có phải là quá trình Zombie không (rất có thể):

ps -Al

Bạn sẽ thấy một cái gì đó như:

0 Z  1000 24589     1  0  80   0 -     0 exit   ?        00:00:00 soffice.bin <defunct>

(Lưu ý "Z" bên trái)

Nếu cột thứ 5 không phải là 1, thì có nghĩa là nó có một quá trình cha. Hãy thử giết id quá trình cha mẹ .

Nếu PPID của nó = 1, ĐỪNG GIẾT NÓ !! , nghĩ rằng những thiết bị hoặc quy trình khác có thể liên quan đến nó.

Ví dụ: nếu bạn đang sử dụng thiết bị được gắn hoặc samba, hãy thử ngắt kết nối thiết bị. Điều đó có thể giải phóng quá trình Zombie.

LƯU Ý : Nếu ps -Al(hoặc top) hiển thị "D" thay vì "Z", nó có thể liên quan đến ngàm từ xa (như NFS). Theo kinh nghiệm của tôi, khởi động lại là cách duy nhất để đi đến đó, nhưng bạn có thể kiểm tra các câu trả lời khác bao gồm trường hợp đó chi tiết hơn.


1
Gửi SIGCHLD đến quy trình cha mẹ có thể khiến cha mẹ nhận ra quy trình đã chết. Điều này sẽ hoạt động ngay cả khi PPID = 1. Điều này thường được gửi bởi kernel, nhưng cũng có thể được gửi cho cha mẹ thông qua kill (kill -17 trên Linux, kiểm tra các trang trên * nix khác). Cách sử dụng này sẽ không thực sự "giết" cha mẹ, mà là (thông báo lại) thông báo rằng một đứa trẻ đã chết và cần được dọn dẹp. Lưu ý rằng sigchld phải được gửi đến cha mẹ của zombie chứ không phải chính zombie.
Stephanie

10

Quá trình init miễn dịch với SIGKILL.

Điều này cũng đúng với các luồng nhân, tức là "các quy trình" có PPID bằng 0.


1
Nhiệm vụ hạt nhân cũng có thể miễn dịch với SIGKILL. Điều này thường xảy ra đủ với Btrfs.
Tobu

9

Như những người khác đã đề cập, một quá trình trong giấc ngủ không bị gián đoạn có thể bị giết ngay lập tức (hoặc, trong một số trường hợp, tất cả). Đáng lưu ý rằng một trạng thái quy trình khác, TASK_KILLABLE, đã được thêm vào để giải quyết vấn đề này trong một số trường hợp nhất định, đặc biệt là trường hợp phổ biến trong đó quy trình đang chờ trên NFS. Xem http://lwn.net/Articles/288056/

Thật không may, tôi không tin rằng nó được sử dụng ở bất cứ đâu trong kernel trừ NFS.


Tôi gặp vấn đề khi giết một lsquá trình truy cập vào một sshfsmount, khi máy chủ từ xa không thể truy cập được. Có giải pháp nào cho FUSE hoặc sshfs, mà tôi có thể sử dụng trong tương lai để tránh những tình huống như vậy không? 2.6.30 kernel
imz - Ivan Zakharyaschev 28/03/13

@imz Một lời khuyên từ Gilles (để giết sshfs) là có - unix.stackexchange.com/a/5648/4319 .
imz - Ivan Zakharyaschev 30/03/13

6

Làm một kịch bản nhỏ giúp tôi rất nhiều hãy xem!

Bạn có thể sử dụng nó để giết bất kỳ tiến trình nào có tên đã cho trong đường dẫn của nó (chú ý đến điều này !!) Hoặc bạn có thể giết bất kỳ quy trình nào của người dùng đã cho bằng cách sử dụng tham số "-u username".

#!/bin/bash

if [ "$1" == "-u" ] ; then\n
        PID=`grep "$2" /etc/passwd | cut -d ":" -f3`
        processes=`ps aux | grep "$PID" | egrep -v "PID|ps \-au|killbyname|grep" | awk '{ print $2}'`
        echo "############# Killing all processes of user: $2 ############################"
else
        echo "############# Killing processes by name: $1 ############################"
        processes=`ps aux | grep "$1" | egrep -v "killbyname|grep" | awk '{ print $2}' `
fi


for process in $processes ; do
        # "command" stores the entire commandline of the process that will be killed
        #it may be useful to show it but in some cases it is counter-productive
        #command=`ps aux | grep $process | egrep -v "grep" | awk '{ print $2 }'`
        echo "Killing process: $process"
        echo ""
        kill -9 $process
done

4
Thay vì chỉ liên kết với nó, thay vào đó bạn có thể đăng mã ở đây.
tshepang

3
Thêm một chút mô tả với (hoặc ít nhất là thay vì) của mã ...
vonbrand

Yup nhưng "$ name" được tổng hợp nhiều hơn ... nó sẽ giết bất kỳ quá trình nào với "$ name" trong đường chạy của nó. Có thể rất hữu ích khi bạn có những dòng lệnh khổng lồ này và bạn không biết tên quy trình là gì.
user36035

5

Có những trường hợp ngay cả khi bạn gửi kill -9 đến một tiến trình, pid đó sẽ dừng lại, nhưng quá trình sẽ tự động khởi động lại (ví dụ, nếu bạn thử với gnome-panelnó, nó sẽ khởi động lại): đó có thể là trường hợp ở đây không?


8
Khi một cái gì đó như thế này xảy ra, PID thực sự thay đổi. Vì vậy, tôi sẽ nhận thấy.
tshepang

2

từ đây ban đầu :

kiểm tra nếu strace cho thấy bất cứ điều gì

strace -p <PID>

thử gắn vào quy trình với gdb

gdb <path to binary> <PID>

nếu quá trình tương tác với một thiết bị mà bạn có thể ngắt kết nối, hãy tháo mô-đun hạt nhân hoặc ngắt kết nối / rút phích cắm vật lý ... thì hãy thử điều đó.


Đã làm cho tôi! (rút phích cắm thiết bị USB đang treo văn bản siêu phàm)
nmz787

1

Tôi đã có loại vấn đề này. Đây là một chương trình mà tôi đã khởi chạy stracevà bị gián đoạn với Ctrl+ C. Nó đã kết thúc ở Ttrạng thái (truy tìm hoặc dừng lại). Tôi không biết chính xác nó đã xảy ra như thế nào, nhưng nó không thể giết được SIGKILL.

Tóm lại, tôi đã giết nó với gdb:

gdb -p <PID>
> kill
Kill the program being debugged? (y or n) y
> quit

-1

Dựa trên manh mối từ câu trả lời của gilles, tôi đã có một quá trình được đánh dấu "Z" ở đầu (tính <defunct>bằng ps) đang sử dụng tài nguyên hệ thống, nó thậm chí còn có một cổng mở là LISTEN'ing và bạn có thể kết nối với cổng đó. Điều này là sau khi thực hiện một kill -9trên nó. Cha mẹ của nó là "1" (tức là init) vì vậy về mặt lý thuyết, nó chỉ nên được lặp lại và biến mất. Nhưng không phải, nó vẫn lảng vảng xung quanh, mặc dù không chạy và "không chết"

Vì vậy, trong trường hợp của tôi, đó là zombie nhưng vẫn tiêu tốn tài nguyên ... FWIW.

Và nó đã không thể đánh bằng bất kỳ số lượng kill -9's

Và cha mẹ của nó là initnhưng nó đã không được gặt hái (làm sạch). Tức là initđã có một đứa trẻ zombie.

Và khởi động lại là không cần thiết để khắc phục vấn đề. Mặc dù khởi động lại "sẽ có tác dụng" xung quanh vấn đề / làm cho nó tắt nhanh hơn. Chỉ cần không duyên dáng, mà vẫn có thể.

Và đó là một cổng LISTEN được sở hữu bởi một quá trình zombie (và một vài cổng khác giống như trạng thái CLOSE_WAIT được kết nối localhost với localhost). Và nó thậm chí vẫn chấp nhận kết nối. Ngay cả như một thây ma. Tôi đoán nó đã không được dọn dẹp các cổng nhưng các kết nối đến vẫn được thêm vào hồ sơ tồn đọng của cổng nghe tcp, mặc dù chúng không có cơ hội được chấp nhận.

Nhiều trong số trên được tuyên bố là "không thể" trên các địa điểm khác nhau trong các interwebs.

Hóa ra tôi có một luồng nội bộ trong đó đang thực hiện một "cuộc gọi hệ thống" (trong trường hợp này là ioctl), phải mất vài giờ để quay lại (đây là hành vi dự kiến). Rõ ràng hệ thống không thể giết quá trình "mọi cách" cho đến khi nó trở về từ ioctlcuộc gọi, đoán nó đi vào vùng đất hạt nhân. Sau một vài giờ nó trở lại, mọi thứ đã được dọn sạch và tất cả các ổ cắm đều tự động đóng lại, vv như mong đợi. Đó là một thời gian mòn mỏi trên tử tù! Hạt nhân đã kiên nhẫn chờ đợi để giết nó.

Vì vậy, để trả lời OP, đôi khi bạn phải chờ đợi. Một thời gian dài. Sau đó, giết cuối cùng sẽ mất.

Đồng thời kiểm tra dmesg để xem có hoảng loạn kernel không (tức là lỗi kernel).


Đây dường như là bạn mô tả kịch bản cụ thể của riêng bạn chứ không phải là một câu trả lời cho câu hỏi. Trong trường hợp của bạn, quá trình tự khắc phục do hoạt động lâu dài, một cái gì đó không được đề cập trong câu hỏi. Tuy nhiên, bạn được hoan nghênh đưa ra một câu hỏi mới và cung cấp câu trả lời cho nó. Mặc dù tôi sợ rằng câu hỏi có thể bị đóng là "không thể lặp lại", vì kết quả là cụ thể cho việc thực hiện của bạn.
Centimane

Đúng, tôi đã thêm cách nó trả lời OP, vì nó ... có thể, trong một số trường hợp.
rogerdpack
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.