Меня часто сбивает с толку то, что, хотя я профессионально работал с компьютерами в течение нескольких десятилетий и с Linux в течение десятилетия, я фактически воспринимаю большую часть функциональных возможностей ОС как черный ящик, мало чем отличающийся от магии.
Сегодня я подумал о kill
команде, и хотя я использую ее несколько раз в день (как в «обычном», так и в -9
привычном стиле), я должен признать, что совершенно не представляю, как она работает за кулисами.
С моей точки зрения, если запущенный процесс «завис», я вызываю kill
его PID, а затем он внезапно перестает работать. Магия!
Что на самом деле там происходит? Manpages говорят о «сигналах», но это, безусловно, просто абстракция. Отправка kill -9
в процесс не требует взаимодействия процесса (например, обработки сигнала), он просто убивает его.
- Как Linux не дает процессу продолжать занимать процессорное время?
- Это удалено из планирования?
- Отключает ли он процесс от своих файловых дескрипторов?
- Как освобождается виртуальная память процесса?
- Есть ли что-то вроде глобальной таблицы в памяти, где 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
и правильно обращаться с этой информацией. Однако у процессов зомби больше нет выделенной памяти, и поэтому они не могут продолжать выполняться.Я думаю, что это достаточно точно. Физическая память отслеживается по странице (одна страница обычно равна фрагменту размером 4 КБ), и эти страницы извлекаются и возвращаются в глобальный пул. Это немного сложнее в том, что некоторые освобожденные страницы кэшируются на случай, если данные, которые они содержат, снова нужны (то есть данные, которые были прочитаны из все еще существующего файла).
Конечно, все сигналы являются абстракцией. Они концептуальны, как «процессы». Я немного играю в семантику, но если вы имеете в виду, что SIGKILL качественно отличается от SIGTERM, то да и нет. Да в том смысле, что его невозможно поймать, но нет в том смысле, что они оба являются сигналами. По аналогии, яблоко - это не апельсин, а яблоки и апельсины, согласно предвзятому определению, оба являются фруктами. SIGKILL кажется более абстрактным, поскольку вы не можете его уловить, но это все еще сигнал. Вот пример обработки SIGTERM, я уверен, что вы видели это раньше:
Этот процесс будет просто спать вечно. Вы можете запустить его в терминале и отправить с помощью SIGTERM
kill
. Это выплевывает такие вещи, как:1066 это мой UID. PID будет тем из оболочки, из которой
kill
выполняется, или PID kill, если вы его разветвляете (kill 25309 & echo $?
).Опять же, нет смысла устанавливать обработчик для SIGKILL, потому что он не будет работать. 3 Если я
kill -9 25309
закончу процесс. Но это все еще сигнал; ядро имеет информацию о том, кто послал сигнал , что это за сигнал и т. д.1. Если вы еще не посмотрели список возможных сигналов , смотрите
kill -l
.2. Другое исключение, как упоминает Тим Пост ниже, относится к процессам в непрерывном сне . Они не могут быть разбужены до тех пор, пока не будет решена основная проблема, и поэтому все сигналы (включая SIGKILL) будут отложены на время. Однако процесс не может специально создать такую ситуацию.
3. Это не означает,
kill -9
что лучше использовать на практике. Мой примерный обработчик плох в том смысле, что он не приводит кexit()
. Настоящая цель обработчика SIGTERM - дать процессу возможность выполнять такие вещи, как очистка временных файлов, а затем добровольно завершать работу. Если вы используетеkill -9
, у вас не будет такого шанса, так что делайте это только в том случае, если часть «добровольно выйти», похоже, не удалась.источник
-9
потому что это реальная проблема, как кто захочет умереть! ;)kill -9
определенных процессов, связанных с вводом / выводом, не будет работать, по крайней мере, не сразу.kill -9
не может быть перехвачено, процесс, получающий его, не может выполнить какую-либо очистку (например, удаление временных файлов, освобождение общей памяти и т. Д.) До своего выхода. Следовательно, используйтеkill -9
(иначеkill -kill
) только в качестве крайней меры. Начните с иkill -hup
и / илиkill -term
сначала, а затем используйтеkill -kill
в качестве последнего удара.Каждый процесс выполняется в запланированное время, а затем прерывается аппаратным таймером, чтобы передать свое ядро ЦП для других задач. Вот почему возможно иметь гораздо больше процессов, чем ядер ЦП, или даже запустить всю операционную систему с большим количеством процессов на одном одноядерном ЦП.
После прерывания процесса управление возвращается к коду ядра. Затем этот код может принять решение не возобновлять выполнение прерванного процесса без какого-либо сотрудничества со стороны процесса. kill -9 может закончить выполнение в любой строке вашей программы.
источник
Вот идеализированное описание того, как убивает процесс. На практике любой вариант Unix будет иметь много дополнительных сложностей и оптимизаций.
Ядро имеет структуру данных для каждого процесса, в которой хранится информация о том, какую память он отображает, какие у него потоки и когда они запланированы, какие файлы у него открыты и т. Д. Если ядро решает уничтожить процесс, оно делает пометку в структура данных процесса (и, возможно, в структуре данных каждого из потоков), что процесс должен быть уничтожен.
Если один из потоков процесса в настоящее время запланирован на другом процессоре, ядро может вызвать прерывание на этом другом процессоре, чтобы заставить этот поток прекратить выполнение быстрее.
Когда планировщик замечает, что поток находится в процессе, который должен быть прерван, он больше не будет его планировать.
Когда ни один из потоков процесса больше не запланирован, ядро начинает освобождать ресурсы процесса (память, файловые дескрипторы и т. Д.). Каждый раз, когда ядро освобождает ресурс, оно проверяет, есть ли у его владельца живые ресурсы. Как только у процесса больше нет живого ресурса (отображение памяти, дескриптор открытого файла и т. Д.), Структура данных для самого процесса может быть освобождена, и соответствующая запись может быть удалена из таблицы процесса.
Некоторые ресурсы могут быть освобождены немедленно (например, освобождение памяти, которая не используется операцией ввода-вывода). Другие ресурсы должны ждать, например, данные, которые описывают операцию ввода-вывода, не могут быть освобождены во время выполнения операции ввода-вывода (во время выполнения прямого доступа к памяти, используемой памяти, и для отмены прямого доступа к памяти требуется связываться с периферией). Драйвер для такого ресурса уведомляется и может попытаться ускорить отмену; как только операция больше не выполняется, драйвер завершит освобождение этого ресурса.
(Запись в таблице процессов на самом деле является ресурсом, принадлежащим родительскому процессу, который освобождается, когда процесс умирает, и родитель подтверждает событие .)
источник