我看到this answer是一个栈溢出问题,它说在c程序的最后释放内存实际上是有害的,因为它将无法使用的变量移到系统内存中。
我很困惑,为什么C中的free()方法会执行与操作系统在程序结尾处回收堆不同的任何事情。
有人知道在内存管理方面free()和终止之间是否存在真正的区别,如果有,操作系统如何将这两个区别对待?
例如
这两个简短程序之间会发生什么不同吗?
void main() {
int* mem = malloc(1);
return 0;
}
void main() {
int* mem = malloc(1);
free(mem);
return 0;
}
答案 0 :(得分:6)
否,与exit
或abort
一样终止程序不会以与free
相同的方式回收内存。使用free
会导致某些活动,当操作系统丢弃malloc
和free
维护的数据时,这些活动最终将无效。
exit
有一些复杂之处,因为它不会立即终止程序。现在,让我们考虑立即终止程序的效果,然后再考虑以后的复杂性。
在通用多用户操作系统中,当进程终止时,操作系统会释放其用于其他目的的内存。 1 在很大程度上,这仅意味着操作系统系统执行一些会计操作。
相反,当您调用free
时,程序中的软件将运行,并且它必须查找要释放的内存的大小,然后将有关该内存的信息插入其正在维护的内存池中。这样的分配可能有成千上万。释放所有数据的程序可能必须执行对free
的数千次调用。但是,最后,当程序退出时,free
产生的所有更改都将消失,因为操作系统将丢弃有关该内存池的所有数据-所有数据都位于该操作的内存页中系统不保留。
因此,就此而言,the answer you link to是正确的,调用free
是浪费。而且,正如所指出的那样,必须遍历程序中的所有数据结构以获取它们中的指针,以便它们所指向的内存可以被释放,如果这些数据结构已被换出,则它们将被读入内存中。到磁盘。对于大型程序,可能需要花费大量时间和其他资源。
另一方面,不清楚是否很容易避免多次调用free
。这是因为释放内存并不是终止程序唯一需要清除的内容。程序可能希望将最终数据写入文件或将最终消息发送到网络连接。此外,程序可能没有直接建立所有这些上下文。大多数大型程序都依赖于软件层,并且每个软件包可能都设置了自己的上下文,并且通常没有提供任何方法告诉其他软件“我现在要退出。完成有价值的上下文,但是跳过所有的内存释放。”因此,所有需要的清理任务可能会与自由内存任务交织在一起,并且可能没有解开它们的好方法。
通常应编写软件,以便在程序突然中止时不会有任何可怕的事情发生(因为这可能是由于断电而引起的,而不仅仅是故意的用户操作)。但是,即使程序可以忍受中止,但正常退出仍然会有价值。
回到exit
,调用C exit
例程不会立即退出程序。调用退出处理程序(在atexit
中注册),刷新流缓冲区,并关闭流。您调用的所有软件库都可能设置了自己的退出处理程序,以便它们可以在程序退出时完成。因此,如果您要确保程序中使用的库在结束程序时没有调用free
,则必须调用abort
,而不是exit
。但是通常最好以优雅的方式结束程序,而不是中止程序。调用abort
不会调用出口处理程序,刷新流,关闭流或执行exit
所做的其他结束代码-程序调用{{1}}时数据可能会丢失。
1 释放内存并不意味着它立即可用于其他目的。具体结果取决于内存的每一页。例如:
答案 1 :(得分:4)
这两个简短程序之间会发生什么不同吗?
简单的答案是:这没有什么区别,两种情况下内存都释放给系统。严格来说,调用border-radius
并不是必须的,并且确实会带来无穷的开销,但是在尝试跟踪更复杂的程序中的内存泄漏时可能会很有用。
终止程序是否以与
free()
相同的方式回收内存?
不完全是:
free
分配了多少内存块,这一切都可以高效完成。malloc()
使程序可以进一步使用内存块供以后对free()
或malloc()
的调用。根据其大小和堆的实现,此释放的块可能会或可能不会返回给操作系统供其他程序使用。同样值得一提的是碎片问题,在该问题中,释放的内存小块可能无法用于较大的分配,因为它们被分配的块包围。 C堆不执行打包或碎片整理,它只是合并相邻的空闲块。在离开程序之前释放所有分配的块可能对调试有用,但可能很复杂且很耗时,而对于程序终止后由系统重用内存不是必需的。答案 2 :(得分:2)
free()
是用户级别的内存管理功能,取决于您当前正在使用的malloc
实现。用户级分配器可能会维护内存块的链表,而malloc / free将获取适当大小的块/将其放回原处。
exit()
销毁地址空间和所有区域。
这与malloc
堆以及用于管理进程地址空间的其他一些区域和内核数据结构有关:
每个地址空间由许多页面对齐的区域组成 正在使用的内存数量。它们从不重叠并代表一组 包含彼此相关的页面的地址 保护条款和目的。这些区域由 struct vm_area_struct,大致类似于 BSD中的vm_map_entry结构。为了清楚起见,区域可以代表 与malloc()一起使用的进程堆,malloc()是内存映射文件,例如 共享库或分配给它的匿名内存块 mmap()。该区域的页面可能仍然需要分配,例如 活动和居民或已被调出页面
参考:https://www.kernel.org/doc/gorman/html/understand/understand007.html
答案 3 :(得分:2)
精心设计的程序在退出时释放内存的原因是为了检查内存泄漏。如果您的应用程序级内存分配在上次取消分配之后没有变为零,则说明您的内存存在未被正确管理的内存,并且代码中可能存在内存泄漏。
这两个简短程序之间会发生什么不同吗?
是
我很困惑,为什么C中的free()方法会执行与操作系统在程序结尾处回收堆不同的任何事情。
操作系统在页面中分配内存。堆管理器(例如malloc / free实现)从操作系统分配页面,并将页面细分为较小的分配。调用free()通常会将内存返回到堆中。他们不会将页面返回到操作系统。