假设我用 c/c++ 创建了一个程序,我在其中手动分配了一些变量。然后在运行程序时,我发送一个中断信号(Ctrl-C)。这些变量是否从内存中释放,或者它们会占用空间直到系统关闭?
另外,如果我刚刚创建了未手动分配的整数,这些变量是驻留还是立即删除,该怎么办?
我认为分配的变量将保留,常规变量将被删除(因为堆栈)。如果是这种情况,有什么办法可以在程序停止后从内存中释放分配的变量吗?
只是好奇。 :)
答案1
进程由内核管理。内核不关心程序员如何分配变量。它只知道某些内存块属于该进程。 C 运行时将 C 内存管理功能与内核功能相匹配:自动变量进入称为“堆栈”的内存块,动态存储(malloc
和朋友)进入称为“堆”的内存块。该进程调用系统调用,例如sbrk
和mmap
获取粒度为内存管理单元页面。在这些块内,运行时确定在哪里放置自动变量和动态分配的对象。
当进程死亡时,内核会更新其内存管理表,以记录每个 MMU 页,该进程不再使用该页。无论进程如何退出,无论是其自身的违规(通过调用系统调用)还是非违规(被信号杀死),这种情况都会发生。不再被任何进程使用的页面被标记为可重用。
释放不再使用的动态分配的存储通常是良好的卫生习惯,因为您永远不知道一段代码何时可以在长时间运行的程序中重用。但是当一个进程死亡时,操作系统将释放其所有资源:内存、打开的文件等。
操作系统不会自动清理的唯一资源是设计为在操作系统上具有全局范围的资源,例如临时文件。
答案2
每当进程正常退出或通过、SIGINT
等退出时,都会调用系统调用。该调用的部分工作是回收该进程正在使用的任何资源。 本质上,每当操作系统看到返回退出状态(成功或失败)时,就会发生两件事:SIGTERM
SIGKILL
exit
exit
SIGCHLD
发送到父进程,让父进程知道子进程已经死亡exit
调用系统调用,这将清理刚刚死亡的进程使用的资源
即使对于僵尸进程和孤儿进程,操作系统也会分配一个特殊的进程来捕获它们的退出代码,然后调用exit
系统调用。
然而,这并不意味着您可以free()
在代码中不使用它。如果不这样做,软件的内存需求将会增加,从而降低整个系统的速度。任何不再需要的东西都应该被释放。
答案3
如果某些内存位需要清零(例如密码或私钥),那么您将需要一个信号处理程序来调用memset(3)
或在进程出现之前执行任何操作。也可以看看钠,其中有一些与此相关的方便且可移植的例程:sodium_mlock
,sodium_memzero
等。内核可以在每个进程退出后始终将所有内存归零,但这无疑会减慢系统速度。
如有必要,先前使用的(但可能未归零的)内存将被内核重用;提供手动内存分配的语言的程序员必须意识到他们的数据结构可能包含谁知道来自某些先前程序的内容(-Wuninitialized
编译器标志在这里相关)。
至于 StephenKitt 声称所有分配始终归零的说法,我想您可以根据该假设编写代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
int i, blahblah[1000000];
for (i = 0; i < 1000000; i++) {
if (blahblah[i] != 0) {
printf("whoops, %d at %d ain't zero\n", blahblah[i], i);
}
}
exit(EXIT_SUCCESS);
}