我在linux下开发了一个包含无限循环while(1)
的C应用程序。 有一些指针是dynamic分配的,在无限循环下是有用的,所以唯一一次释放内存是在通过ctrl-z
, ctrl-c
, kill -9 apppid
, killall appname
中断while(1)
之后。 所以我的想法是,我把新的处理程序释放内存中断事件信号。
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
不会启动处理程序。
有人知道为什么吗? 有没有build议来纠正它?
SIGKILL的全部意义在于无论如何杀死进程。 这就是为什么你不能处理它。
在大多数情况下,您从SIGTERM开始,为流程提供一个很好的退出机会。 当SIGTERM不起作用时,通常使用SIGKILL作为最后的手段。 毕竟,SIGTERM的预期行为是过程退出。 如果不是,你就知道有什么地方是错的。
从手册
SIGTERM信号是用于导致程序终止的通用信号。 不像SIGKILL,这个信号可以被阻塞,处理和忽略。 礼貌地要求程序终止是正常的方法。
…
SIGKILL信号用于立即终止程序。 它不能被处理或忽略,因此总是致命的。 也不可能阻止这个信号。
在同一个文件中,你也可以阅读这个有趣的东西
事实上,如果SIGKILL无法终止进程,那么它本身就构成了一个您应该报告的操作系统错误。
你不能捕获SIGKILL
和SIGSTOP
信号。 所以你的信号处理程序不会做任何事情。 当你的进程接收到SIGKILL时,你无能为力,更不用说任何内存清理了。 在Linux上,内存将在程序退出时被清除,所以这可能不是问题。 通常这样的退出清理是为SIGTERM完成的。
正确的答案是不要发送SIGKILL( kill -9
只能在kill
本身不起作用的情况下使用)。 这不是要求流程自行终止的方法。 首先发送SIGTERM,如果不起作用,则发送SIGKILL。
man 7 signal
当你SIGKILL一个进程,你不要求它很好地终止。 你要求内核停止进程的进一步执行。 因此,进程不知道它已经收到SIGKILL。
但是对你来说无关紧要,因为只有在SIGTERM没有成功的时候SIGKILL才会被发布。
所以我的想法是,我把新的处理程序释放内存的中断事件信号。
不需要! 在进程终止之后,无论原因是什么,所有内存都从内核中释放。 所以你没有必要手动去做
有了IPC的资源和信号,你将会遇到这个问题,根本无法妥善处理。
你的问题是由于几个原因不适当的。
首先,当你的进程终止时, malloc
内存被释放。 如果现代架构不能自动完成,大多数机器将完全无法使用。
其次,一些信号和一些过程终止的方式是不可捉摸的。 所以对于这些,无论如何都没有希望做修复工作。 终止一个执行没有太多清理的方法有一些信号, abort
, quick_exit
, _Exit
。
第三,使用信号处理器进行清理工作是完全矫枉过正的。 C库有为此设计的atexit
和at_quick_exit
(自C11)处理程序。 所以如果在执行结束时(比如写一些最后的消息到一个套接字,清理文件或者共享内存)你必须做一些特殊的事情,可以使用为此发明的工具。
根据定义你不能捕获SIGKILL(kill -9)。 这意味着作为一个“最后的手段”杀死一个进程,所以出于这个原因,这个进程一定不能赶上它。 对于一个友好的终止请求,检查SIGTERM(杀死-15或没有具体的值杀死)。
但是,除非你需要做非常具体的清理行动,否则你一般不应该去捕捉这样的事件。 内存将被释放,但操作系统; 没有必要让你的程序捕捉信号只是为了释放内存。
man 7 signal
将显示
SIGKILL 9 Term Kill signal
这意味着,当这个信号到来时,你不再控制代码。
从signal
定义手册引用:
The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.