Приложение c/linux с бесконечным циклом: освободить память, если вызывается команда kill -9

Я разработал приложение C в Linux, которое содержит бесконечный цикл while(1). Есть некоторые указатели, которые распределяются динамически и полезны в бесконечном цикле, поэтому единственный раз, когда можно освободить память, это после прерывания while(1) на ctrl-z, ctrl-c, kill -9 apppid, killall appname. Итак, идея состоит в том, что я связываю новый обработчик, который освобождает память с сигналами событий прерывания.

void deallocatehandler(int signal){ printf("Memory Deallocation\n"); exit(0);}

int main(){
    signal(SIGINT, &deallocatehandler);
    signal(SIGTSTP, &deallocatehandler);
    signal(SIGKILL, &deallocatehandler);

    while(1){
        /**
        Some code here
        **/
    }
}

Если я нажимаю ctrl-c или ctrl-z, вызывается обработчик, но проблема связана с SIGKILL. Команды kill -9 и killall не запускают обработчик.

Кто-нибудь знает, почему? и есть предложения по исправлению?


person Kallel Omar    schedule 24.10.2017    source источник
comment
С SIGKILL не справиться, читайте мануал.   -  person Stargateur    schedule 24.10.2017
comment
@Stargateur, так в чем идея освободить память, если мы вызовем команду kill?   -  person Kallel Omar    schedule 24.10.2017
comment
Вы можете обратиться к вопросу по этой ссылке изящное завершение"> stackoverflow.com/questions/7376228/   -  person Feten besbes    schedule 24.10.2017
comment
Ну, вы не можете с SIGKILL, этот сигнал используется для остановки любого процесса. Мы используем SIGTERM для правильного завершения процесса.   -  person Stargateur    schedule 24.10.2017
comment
Возможный дубликат C++: как закрыть TCP сокет (сервер) при получении SIGKILL   -  person n. 1.8e9-where's-my-share m.    schedule 24.10.2017
comment
Даже для сигналов, отличных от SIGKILL и SIGSTOP (которые оба не могут быть перехвачены), malloc() и free() небезопасно использовать в любом обработчике сигналов.   -  person joop    schedule 24.10.2017
comment
Кроме того, вы можете безопасно вызывать функции, безопасные для асинхронных сигналов, только из обработчика сигналов. Такие функции, как malloc(), free() и даже printf(), не безопасны для асинхронных сигналов и не должны вызываться из обработчика сигналов.   -  person Andrew Henle    schedule 24.10.2017


Ответы (7)


Весь смысл SIGKILL в том, чтобы убить процесс, несмотря ни на что. Вот почему вам не разрешено с этим справляться.

В большинстве случаев вы начинаете с SIGTERM, чтобы дать процессу возможность завершиться красиво. SIGKILL обычно используется в крайнем случае, когда SIGTERM не работает. В конце концов, ожидаемое поведение SIGTERM заключается в завершении процесса. Если это не вы знаете, что что-то не так.

Из руководства.

Сигнал SIGTERM — это общий сигнал, используемый для завершения программы. В отличие от SIGKILL, этот сигнал можно блокировать, обрабатывать и игнорировать. Это нормальный способ вежливо попросить программу завершить работу.

...

Сигнал SIGKILL используется для немедленного завершения программы. С ним нельзя справиться или проигнорировать, и поэтому он всегда смертелен. Также невозможно заблокировать этот сигнал.

В этом же документе можно прочитать и вот эту интересную вещь

На самом деле, если SIGKILL не может завершить процесс, это само по себе является ошибкой операционной системы, о которой вы должны сообщить.

person klutt    schedule 24.10.2017

Вы не можете поймать сигналы SIGKILL и SIGSTOP. Так что ваш обработчик сигналов ничего не сделает. Вы ничего не можете сделать, когда ваш процесс получает сигнал SIGKILL, не говоря уже об очистке памяти. В Linux память очищается при выходе из программы, так что это, вероятно, не проблема. Обычно такая очистка при выходе делается для SIGTERM.

Правильный ответ - не отправлять SIGKILL (kill -9 следует использовать только в том случае, если сам kill не работает). Это не способ запросить процесс завершить себя. Сначала отправьте SIGTERM, а если это не сработает, отправьте SIGKILL.

person P.P    schedule 24.10.2017

man 7 signal

Когда вы SIGKILL процесс, вы не просите, чтобы он завершился красиво. Вы просите ядро ​​остановить дальнейшее выполнение этого процесса. Таким образом, процесс не может знать, что он получил сигнал SIGKILL.

Но для вас это не должно иметь значения, так как SIGKILL будет выдаваться только тогда, когда SIGTERM не показал успеха.

person MikaDo-    schedule 24.10.2017

Итак, идея состоит в том, что я связываю новый обработчик, который освобождает память с сигналами событий прерывания.

Не требуется! После завершения процесса, какой бы ни была причина, вся память освобождается от ядра. Так что вам не нужно делать это вручную.

С ресурсами IPC и семафорами у вас будет эта проблема, с которой вообще нельзя справиться должным образом.

person Klaus    schedule 24.10.2017
comment
Я имею в виду память, динамически выделяемую с помощью malloc или calloc. Он должен быть освобожден free. Если мы не освободим его в приложении, у нас будет мусор. - person Kallel Omar; 24.10.2017
comment
@KallelOmar: Нет, динамическая выделенная память будет освобождена после завершения процесса. Просто выделите огромное количество данных, завершите процесс и повторите это 1000 раз. У вас вообще не будет нехватки памяти, потому что ядро ​​сделает всю работу! - person Klaus; 24.10.2017
comment
вот почему я подумал добавить дескриптор соответствующего сигнала, чтобы освободить динамическую выделенную память перед выходом - person Kallel Omar; 24.10.2017
comment
Еще раз: нельзя! kill -9 завершает процесс, обработчик не вызывается! И нет необходимости в обработчике, так как ядро ​​​​освобождает ресурсы вашей памяти. Но еще раз: если вы используете ресурсы IPC или другие, ваша система сохраняет эти ресурсы, и вам приходится решать эту проблему ВНЕ вашего приложения. - person Klaus; 24.10.2017
comment
@KallelOmar: Почему ты не читаешь мой ответ? Я говорю: ядро ​​освободит ваши ресурсы. Неважно, как это работает. Так что просто забудьте! Просто не будет утечки памяти ПОСЛЕ завершения процесса. - person Klaus; 24.10.2017

Ваш вопрос некорректен по нескольким причинам.

Во-первых, память malloced освобождается при завершении вашего процесса. Большинство машин были бы совершенно непригодны для использования, если бы современные архитектуры не делали это автоматически.

Во-вторых, некоторые сигналы и некоторые способы завершения процесса не перехватываются. Так что для этих нет никакой надежды делать ремонт в любом случае. Среди методов, которые завершают выполнение без особой очистки, есть некоторые сигналы, abort, quick_exit, _Exit.

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

person Jens Gustedt    schedule 26.10.2017
comment
Функции atexit и at_quick_exit - это что-то новое для меня, что я узнал из вашего ответа, спасибо :) - person Kallel Omar; 26.10.2017

Вы не можете поймать SIGKILL (kill -9) по определению. Это предназначено как «последнее средство» для уничтожения процесса, поэтому по этой причине процесс не должен быть в состоянии его перехватить. Для дружественного запроса на завершение проверьте наличие SIGTERM (kill -15 или kill без определенного значения).

Но в целом вы не должны перехватывать такие события, если только вам не нужно выполнять очень специфические действия по очистке. Память будет освобождена, но операционная система; вашей программе не нужно ловить сигналы только для освобождения памяти.

person slingeraap    schedule 24.10.2017

man 7 signal покажет

SIGKILL       9       Term    Kill signal

что означает, что вы больше не можете контролировать код, когда приходит этот сигнал.

Цитата из руководства по определению signal:

The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
person alinsoar    schedule 24.10.2017