内存泄漏到底能走多远?

Dil*_*rix 118 c c++ memory memory-leaks

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

如果答案在语言与语言之间差异很大,那么让我们关注C(++).

请注意短语的双曲线使用,"就像没有明天","悬挂......就像脏衣服".不安全的*malloc*会伤害你所爱的人.此外,请小心脏衣服.

Jon*_*oni 110

否.操作系统在进程退出时释放进程持有的所有资源.

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

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

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

  • 请注意,并非操作系统可以释放所有资源.网络连接,数据库事务等未明确关闭它们可能会导致一些不良结果.不关闭网络连接可能会导致服务器认为您无限期仍处于活动状态,对于限制活动连接数的服务器,可能会意外导致拒绝服务.不关闭数据库事务可能会导致您丢失未提交的数据. (29认同)
  • *"操作系统在进程退出时释放进程持有的所有资源."*严格来说并非如此.例如,在(至少)Linux上,SysV信号量和其他IPC对象在进程退出时不会被清除.这就是为什么有用于手动清理的`ipcrm`,http://linux.die.net/man/8/ipcrm. (19认同)
  • 此外,如果一个对象有一个它维护的临时文件,那么_clearly_将不会被清除. (7认同)
  • RTOS中的一个常见范例是单进程,多线程模型,并且"任务"之间没有内存保护.通常有一堆.这当然是VxWorks的工作方式 - 而且可能仍然如此. (5认同)

oua*_*uah 47

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

  • 这或多或少是因为C标准谈论C程序,而不是C恰好运行的操作系统...... (20认同)
  • @vonbrand C标准可能有一段说明当`main`返回由`malloc`分配的所有内存时释放.例如,它表示在程序终止之前所有打开的文件都已关闭.对于分配了我的`malloc`的内存,它没有被指定.当然,我关于操作系统的句子描述的是通常所做的不是标准规定的内容,因为它没有对此进行任何说明. (5认同)
  • @ouah:"_ when_ main返回......".这是一个假设.我们必须考虑"_if_主要回报......".`std :: atexit`也考虑通过`std :: exit`终止程序,然后还有`std :: abort`和(C​​ ++ specific)`std :: terminate`. (2认同)

Abh*_*jit 28

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

从技术上讲,程序终止,但由于它仍然驻留在内存中,除非卸载程序,否则不会释放任何内存泄漏.

因此,您可以将此视为另一种情况,除了操作系统不回收内存,因为它是错误的,或者因为嵌入式操作系统是为此而设计的.

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

  • @zhermes:DOS(就像CP/M,它的祖先)并不是你所谓的现代意义上的操作系统.它实际上只是一组I/O实用程序,可以通过与命令处理器捆绑在一起的标准方式调用,这样可以让您一次运行一个程序.没有进程的概念,内存既不虚拟也不受保护.TSR是一个有用的黑客,它可以告诉系统他们占用了64K的空间,并将自己挂钩到中断,以便他们被调用. (2认同)

And*_*tur 8

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

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

故事的道德,总是清理自己.不要让事情摇摇欲坠.在你之后不要依赖操作系统清理.自己清理干净.


joh*_*ohn 7

这更可能取决于操作系统而非语言.最终,任何语言的任何程序都将从操作系统中获取内存.

我从来没有听说过程序退出/崩溃时没有回收内存的操作系统.因此,如果你的程序在它需要分配的内存上有一个上限,那么分配和永不释放是完全合理的.


小智 5

所有值得拥有标题的操作系统都会清理您终止后的过程.但是总会有无法预料的事件,如果它以某种方式被拒绝访问并且一些可怜的程序员没有预见到这种可能性会怎么样,所以它不会再稍后再尝试呢?如果内存泄漏是关键任务,那么总是更安全地清理自己 - 否则,如果这种努力代价高昂,那么IMO的努力就不值得.

编辑:如果内存泄漏位于会积累的位置(如循环中),则需要清除内存泄漏.我所说的内存泄漏是在整个程序过程中不断积累的内存泄漏,如果你有任何其他类型的泄漏,它很可能迟早会成为一个严重的问题.

在技​​术方面,如果你的泄漏是内存"复杂性"O(1)它们在大多数情况下都很好,O(logn)已经令人不愉快(在某些情况下是致命的)和O(N)+无法忍受.


Kaz*_*Kaz 5

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

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

我正在研究的一个程序,某个测试用例需要30秒或更长时间才能退出程序,因为它是通过所有动态内存的图形递归并逐个释放它.

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