不对应free的malloc函数是否总是会导致内存泄漏?

4

malloc没有相应的free会不会总是导致内存泄漏,还是有情况下不会产生内存泄漏呢?


内存会保留,无论你是否需要,直到被释放。但是在源代码中,您不需要它们之间的一对一对应,只要您分配的所有内容都被释放(例如mallocfree可以在不同的函数中使用,或者一个free命令行可以执行多次来释放在代码不同部分分配的多个块等)。此外,当程序退出时,剩余分配的任何内容通常都会被释放。 - Dmitri
基本上,在运行时对 malloc 等的调用次数应该与对 free 的调用次数相匹配,但不一定与源代码中的出现次数相匹配。 - Dmitri
realloc(malloc(1000),0) 可以在没有 free() 的情况下释放已分配的内存。 - chux - Reinstate Monica
4个回答

5
这取决于你如何定义“内存泄漏”。如果你将其定义为在程序退出时有任何未释放的具有分配存储期限的对象,那么是的,这就是一种泄漏。这就是像valgrind这样的工具所报告的。然而,这根本不是一个有用的定义。
我对内存泄漏的定义大致上是指程序在其生命周期内总内存消耗的无界增加,尽管有一个有界的工作集。例如,如果我在浏览器中始终最多打开10个选项卡,访问同样的10个站点,但内存使用量仍然无限增加,那就是一种内存泄漏。另一方面,一个程序分配一个缓冲区来加载整个文件到内存中,加载文件,反向打印它,然后退出而不释放内存,这并没有内存泄漏。
特别重要的一种情况是,使用call_once控制生成的运行时分配常量表的任何代码(对于不能做出关于其运行环境的任何假设的通用代码)都不仅不是泄漏,而且绝对必要。无论您多晚尝试释放这些表格,都有可能有代码(在另一个线程、或者是atexit处理程序等)在释放后尝试访问它,而call_once类型的接口故意不提供任何同步任何访问的方法,除了第一次调用(这是它们避免在每次读取时引入不希望的获取屏障/同步成本的方式)。
请注意,这里的“工作集”概念有些主观,并且高度承载。通常,内存泄漏是软件仍然将某些内容视为其工作集的一部分,而用户不再这样考虑。

1
你忽略了一个事实,即小程序的代码通常被打包并作为可调用函数在另一个程序中重复使用。在这种情况下,分配的存储空间如果在小程序终止时没有被释放,就会导致大型程序内存消耗增加的原因。在这种情况下,你所给出的两个定义是等价的 - 只是适用于不同上下文中相同的代码。 - Peter
1
@Peter:我并没有“错过”它;相反,我们在这个问题上有不同的观点。特别是,“代码”本身并没有内存泄漏或者没有内存泄漏;程序才会有。当然,代码可能会导致程序中出现内存泄漏,以至于无法在任何实际情况下使用它,但真实世界的情况通常不会那么简单。 - R.. GitHub STOP HELPING ICE
@Peter:我添加了一段具体示例的文字,说明为什么能够分配但从不释放的能力很重要。 - R.. GitHub STOP HELPING ICE

2
内存泄漏是指程序分配了内存,但在不再使用时未释放它并且丢失了其地址(由malloc、calloc或realloc返回的指针的值)。由于指针丢失,内存无法被释放并将一直附加到程序,直到退出为止。如果程序退出,则与之关联的所有内存都将被操作系统回收(除非超出此问题范围的罕见情况),因此内存泄漏没有后果。如果程序长时间运行,可能一直到系统关闭,附加到程序的未使用内存块不能用于其他目的。如果浪费的内存量很小,也不会产生后果。相反,如果程序继续分配更多的内存并且不释放它,则系统将耗尽程序可用的内存,并返回NULL以进行分配请求,或者在使用虚拟内存以满足请求的同时损害其他程序,并且需要进行长时间的交换操作到存储设备或其他压缩技术。某些时候,系统可能会随机杀死进程以尝试恢复可用内存。这种内存泄漏是有问题的,必须避免。它们在库函数中尤其有问题,这些库函数可能被用于运行时间较长的程序,例如Web浏览器、电子邮件阅读器、文件管理器、媒体播放器、程序管理器等。与其他编程语言不同,C没有嵌入式垃圾收集器来确定哪些分配的内存块仍在使用中,因此程序员有责任跟踪所有已分配的块并尽快释放它们。可以使用高级工具(例如valgrind)来验证程序退出时是否已释放了所有分配的块。虽然没有必要在退出时释放内存,但这是良好的编程实践和确定是否已记录所有分配的内存块的好方法。

1
答案可能取决于malloc的实现,但通常有两种情况下,我们期望malloc不会产生内存泄漏:
  1. 当您将0作为大小参数传递时,某些实现将只返回NULL而不分配任何内容,而其他实现将返回一个唯一的指针,即使这被视为未分配任何字节,您仍将泄漏大约64个字节的记录。

  2. 当发生内存不足时。检查全局变量errno以获得特定值,通常为ENOMEM,以查看是否失败。在这种情况下,malloc也会返回NULL


1
当你定义内存泄漏时,要排除有意保留到程序结束的良性内存分配。+1 - Petr Skocik

0

标准并不要求任何内存泄漏。因此,本身没有任何情况可以保证内存泄漏。

另一方面,标准也不要求在您提到的情况下不发生内存泄漏。

在大多数情况下,程序退出时,所有分配的内存都将被释放。但是,在某些系统(特别是嵌入式系统)上可能会有例外情况。如果这对于您的程序很重要,则不应依赖它。


看起来你把“内存泄漏”定义为“进程已经不存在但仍然分配了内存”。只是想提醒一下,因为我之前没有见过这种定义。 - ikegami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接