繁体   English   中英

终止程序是否以与free()相同的方式回收内存?

[英]Does terminating a program reclaim memory in the same way as free()?

我看到了堆栈溢出问题的答案 ,该问题表明在ac程序的最后释放内存实际上是有害的,因为它会将不会再次使用的变量移动到系统内存中。

我很困惑,为什么C中的free()方法会比在程序结束时回收堆的操作系统做任何不同的事情。

有没有人知道在内存管理方面free()和终止之间是否存在真正的区别?如果是这样,操作系统如何区别对待这两者?

例如

这两个短节目会发生什么不同吗?

void main() {
    int* mem = malloc(1);
    return 0;
}
void main() {
    int* mem = malloc(1);
    free(mem);
    return 0;
}

不,终止程序,如exitabort ,不会以与free相同的方式回收内存。 使用free会导致某些活动在操作系统丢弃mallocfree维护的数据时最终无效。

exit有一些复杂性,因为它不会立即终止程序。 现在,让我们考虑一下立即终止程序的效果,并考虑以后的并发症。

在通用多用户操作系统中,当进程终止时,操作系统释放其用于其他目的的存储器。 1在很大程度上,这仅仅意味着操作系统会执行一些会计操作。

相反,当您调用free ,程序内部的软件会运行,并且必须查找正在释放的内存大小,然后将有关该内存的信息插入到它正在维护的内存池中。 可能有数千或数万(或更多)此类分配。 释放其所有数据的程序可能必须执行数千次free调用。 然而,最后,当程序退出时, free发出的所有更改都将消失,因为操作系统将丢弃有关该内存池的所有数据 - 所有数据都在内存页面中,操作系统无法保留。

所以,在这方面, 你链接的答案是正确的, free电话是一种浪费。 并且,正如它所指出的那样,必须遍历程序中的所有数据结构以获取它们中的指针,以便它们指向的内存可以被释放,从而导致所有这些数据结构在被换出时被读入内存到磁盘。 对于大型程序,可能需要相当长的时间和其他资源。

另一方面,目前尚不清楚是否容易避免许多free电话。 这是因为释放内存不是终止程序必须清理的唯一内容。 程序可能希望将最终数据写入文件或将最终消息发送到网络连接。 此外,程序可能没有直接建立所有这些上下文。 大多数大型程序都依赖于软件层,每个软件包都可能已经建立了自己的上下文,并且通常无法告诉其他软件“我想立即退出。 完成有价值的上下文,但跳过所有释放内存。“因此,所有期望的清理任务可能与自由内存任务交织在一起,并且可能没有好的方法来解开它们。

通常应编写软件,以便在程序突然中止时不会发生任何可怕的事情(因为这可能是由于断电而不仅仅是故意的用户操作)。 但即使一个程序可能能够容忍中止,在优雅的退出中仍然有价值。

返回exit ,调用C exit例程不会立即退出程序。 调用退出处理程序(使用atexit注册),刷新流缓冲区,关闭流。 您调用的任何软件库可能已经设置了自己的退出处理程序,以便在程序退出时可以完成。 所以,如果你想确保你在程序中使用的库在你结束程序时没有free调用,你必须调用abort ,而不是exit 但通常优先的是优雅地结束程序,而不是通过中止。 调用abort不会调用退出处理程序,刷新流,关闭流或执行其他exit代码的exit代码 - 当程序调用abort时数据可能会丢失。

脚注

1释放内存并不意味着它可立即用于其他目的。 具体结果取决于每页内存。 例如:

  • 如果内存与其他进程共享,则它们仍然需要它们,因此通过此进程释放它只会减少使用内存的进程数。 它不能立即用于任何其他用途。
  • 如果内存未被任何其他进程使用但包含从磁盘上的文件映射的数据,则操作系统可能会在需要时将其标记为可用,但暂时不管它。 这是因为您可能会再次运行相同的程序,如果数据仍然在内存中会很好,那么为什么不将它留在原位以防万一呢? 甚至可以由使用相同文件的其他程序使用该数据。 (例如,许多程序可能使用相同的共享库。)
  • 如果内存未被任何其他进程使用,并且程序仅将其用作工作区,而不是从文件映射,则系统可将其标记为立即可用且不包含任何有用的内容。

这两个短节目会发生什么不同吗?

简单的答案是:它没有区别,在两种情况下都会将内存释放到系统中。 调用free()并不是绝对必要的,并且会产生无限小的开销,但在尝试跟踪更复杂程序中的内存泄漏时可能会有用。

终止程序是否以与free相同的方式回收内存?

不完全是:

  • 终止程序会释放程序使用的内存,无论是程序代码,数据,堆栈还是堆。 它还释放了一些其他资源,例如文件句柄,设备句柄,网络套接字......无论使用malloc()分配了多少块内存,所有这些都可以高效完成。
  • 相反, free()使得内存块可供程序进一步使用,以便稍后调用malloc()realloc() 根据其大小和堆的实现,此释放的块可能会也可能不会返回到OS以供其他程序使用。 还值得注意的是碎片问题,其中小块的释放内存可能无法用于更大的分配,因为它们被分配的块包围。 C堆不执行打包或解碎,它只是合并相邻的空闲块。 在离开程序之前释放所有分配的块可能对于调试目的是有用的,但可能是复杂且耗时的,而在程序终止之后系统不需要重用存储器。

free()是用户级内存管理功能,取决于您当前使用的malloc实现。 用户级分配器可能维护内存块的链接列表,malloc / free将采用适当大小的块/将其放回。

exit()销毁地址空间和所有区域。 这与malloc ed堆以及用于管理进程地址空间的一些其他区域和内核数据结构有关:

每个地址空间由正在使用的许多页面对齐的内存区域组成。 它们从不重叠并代表一组地址,这些地址包含在保护和目的方面彼此相关的页面。 这些区域由struct vm_area_struct表示,大致类似于BSD中的vm_map_entry结构。 为清楚起见,区域可以表示与malloc()一起使用的进程堆,内存映射文件(如共享库)或使用mmap()分配的匿名内存块。 该区域的页面可能仍然需要分配,活动和驻留或已被分页

参考: https//www.kernel.org/doc/gorman/html/understand/understand007.html

精心设计的程序在退出时释放内存的原因是检查内存泄漏。 如果在上次重新分配后应用程序级内存分配没有变为零,则表示您的内存未正确管理,并且代码中可能存在内存泄漏。

这两个短节目会发生什么不同吗?

我很困惑,为什么C中的free()方法会比在程序结束时回收堆的操作系统做任何不同的事情。

操作系统在页面中分配内存。 堆管理器(例如malloc / free实现)从操作系统分配页面并将页面细分为较小的分配。 调用free()通常会将内存返回堆中。 它们不会将页面返回到操作系统。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM