121

我多次遇到内存泄漏。通常当我malloc像没有明天一样,或者FILE *像脏衣服一样晃来晃去的时候。我通常假设(阅读:绝望地希望)至少在程序终止时所有内存都被清理了。是否存在程序终止或崩溃时不会收集泄漏内存的情况?

如果答案因语言而异,那么让我们关注 C(++)。

请注意短语的双曲用法,“就像没有明天”和“晃来晃去……像脏衣服一样”。不安全* malloc*ing 会伤害您所爱的人。此外,请谨慎使用脏衣服。

4

9 回答 9

116

不会。操作系统在进程退出时释放进程持有的所有资源。

这适用于操作系统维护的所有资源:内存、打开的文件、网络连接、窗口句柄......

也就是说,如果程序在没有操作系统的嵌入式系统上运行,或者在非常简单或有缺陷的操作系统上运行,则内存可能在重新启动之前无法使用。但如果你处于那种情况下,你可能不会问这个问题。

操作系统可能需要很长时间才能释放某些资源。例如,网络服务器用来接受连接的 TCP 端口可能需要几分钟才能空闲,即使被程序正确关闭。联网的程序也可以保存远程资源,例如数据库对象。当网络连接丢失时,远程系统应该释放这些资源,但它可能需要比本地操作系统更长的时间。

于 2013-03-17T23:00:25.740 回答
48

C 标准没有指定malloc在程序终止时释放分配的内存。这是由操作系统完成的,并不是所有的操作系​​统(通常在嵌入式世界中)都会在程序终止时释放内存。

于 2013-03-17T23:01:17.627 回答
29

由于所有答案都涵盖了现代操作系统问题的大部分方面,但从历史上看,如果您曾经在 DOS 世界中编程过,那么有一个值得一提。终止和驻留(TSR)程序通常会将控制权返回给系统,但会驻留在内存中,可以通过软件/硬件中断来恢复。在这些操作系统上工作时,看到诸如“内存不足!尝试卸载一些 TSR”之类的消息是正常的。

所以从技术上讲,程序终止了,但是因为它仍然驻留在内存中,所以除非你卸载程序,否则任何内存泄漏都不会被释放。

因此,除了操作系统不回收内存之外,您可以认为这是另一种情况,因为它有问题或因为嵌入式操作系统旨在这样做。

我还记得一个例子。客户信息控制系统(CICS) 是一种主要在 IBM 大型机上运行的事务服务器,它是伪对话的。执行时,它处理用户输入的数据,为用户生成另一组数据,传输到用户终端节点并终止。激活注意键后,它会再次恢复处理另一组数据。因为它的行为方式再次从技术上讲,操作系统不会从终止的 CICS 程序中回收内存,除非您回收 CICS 事务服务器。

于 2013-03-18T03:22:37.940 回答
8

正如其他人所说,大多数操作系统将在进程终止时回收分配的内存(可能还有其他资源,如网络套接字、文件句柄等)。

话虽如此,在处理 new/delete(而不是原始 malloc/free)时,内存可能不是您唯一需要担心的事情。在 new 中分配的内存可能会被回收,但可能在对象的析构函数中完成的事情不会发生。也许某些类的析构函数在销毁时将标记值写入文件。如果进程刚刚终止,文件句柄可能会被刷新并回收内存,但不会写入该标记值。

故事的道德,总是在自己之后清理。不要让事情悬而未决。不要依赖操作系统进行清理。自己打扫干净。

于 2013-03-18T00:53:10.173 回答
7

这更可能取决于操作系统而不是语言。最终,任何语言的任何程序都会从​​操作系统中获得它的内存。

我从未听说过在程序退出/崩溃时不回收内存的操作系统。因此,如果您的程序在需要分配的内存上有一个上限,那么只分配而不释放是完全合理的。

于 2013-03-17T23:02:10.033 回答
5

所有当之无愧的操作系统都将清理您的进程在终止后造成的混乱。但是总是有不可预见的事件,如果它以某种方式被拒绝访问并且一些可怜的程序员没有预见到这种可能性,所以它不会稍后再试一次怎么办?如果内存泄漏对任务至关重要,那么清理自己总是更安全 - 否则,如果这项工作代价高昂,IMO 就不值得付出努力。

编辑:您确实需要清理内存泄漏,如果它们在它们会累积的地方,比如在循环中。我所说的内存泄漏是在整个程序过程中不断累积的,如果你有任何其他类型的泄漏,它很可能迟早会成为一个严重的问题。

用技术术语来说,如果您的泄漏是内存“复杂性”O(1),在大多数情况下它们都很好,O(logn) 已经令人不快(在某些情况下是致命的)并且 O(N)+ 无法忍受。

于 2013-03-17T23:18:34.473 回答
5

如果程序曾经变成一个动态组件(“插件”)并加载到另一个程序的地址空间中,这将是很麻烦的,即使在具有整洁内存管理的操作系统上也是如此。我们甚至不必考虑将代码移植到功能较弱的系统上。

另一方面,释放所有内存影响程序清理的性能。

我正在处理的一个程序,某个测试用例需要 30 秒或更长时间才能退出程序,因为它正在遍历所有动态内存的图形并逐个释放它。

一个合理的解决方案是拥有该功能并用测试用例覆盖它,但在生产代码中将其关闭,以便应用程序快速退出。

于 2013-03-18T01:32:20.590 回答
3

POSIX 兼容系统上的共享内存一直存在,直到调用 shm_unlink 或系统重新启动。

于 2013-03-20T08:12:18.703 回答
2

如果您有进程间通信,这可能会导致其他进程永远不会完成和消耗资源,具体取决于协议。

举个例子,当我在打印机作业的中间终止 JVM 时,我曾经尝试用 Java 打印到 PDF 打印机,PDF 假脱机进程仍然处于活动状态,我必须在任务管理器中将其杀死才能完成重试打印。

于 2013-03-18T11:01:02.163 回答