【问题标题】:Does malloc without corresponding free always produce a memory leak?没有相应 free 的 malloc 是否总是会产生内存泄漏?
【发布时间】:2020-03-19 16:46:55
【问题描述】:

malloc 没有对应的free 是否总是会产生内存泄漏,或者是否存在不会产生内存泄漏的情况?

【问题讨论】:

  • 无论您是否需要,内存都会保持分配状态,直到它被释放。但是您不需要在源代码中它们之间存在 1:1 的对应关系,只要您分配的所有内容都被释放(例如,mallocfree 可以在不同的函数中,或者一个 free 行可以执行多次以释放分配在代码不同部分的多个块等)。此外,当程序退出时,仍然分配的任何东西通常都会被释放。
  • 基本上,运行时对malloc等的调用次数应该与对free的调用次数匹配,但不一定与源中出现的次数匹配。
  • realloc(malloc(1000),0) 可以在没有free() 的情况下释放分配的内存。

标签: c memory-leaks malloc free


【解决方案1】:

这取决于您如何定义“内存泄漏”。如果您将其定义为在程序退出时具有已分配存储持续时间的任何未完成对象,那么是的,这是一个泄漏。这就是 valgrind 等工具报告的内容。然而,这根本不是一个有用的定义。

我对内存泄漏的定义大致是程序的总内存消耗在其生命周期内无限制地增加,尽管有一个有限的工作集。例如,如果我总是在浏览器中打开最多 10 个选项卡,访问相同的 10 个站点,但内存使用量不断增加,这就是内存泄漏。另一方面,分配缓冲区以将整个文件加载到内存中,加载文件,反向打印,然后退出而不释放内存的程序没有内存泄漏。

一个特别重要的情况是,没有freemalloc 不仅不是泄漏而且绝对必要(对于不能对其运行的整个程序做出假设的一般代码)是运行时的任何使用- 分配的常量表,其生成由call_once 控制。无论您尝试释放此类表的时间有多晚,代码(在另一个线程中,或atexit 处理程序等)都可能在释放后尝试访问它,并且call_once 类型接口故意不提供除了第一次调用外,任何同步访问的方式(这是他们避免在每次读取时引入不必要的获取障碍/同步成本的方式)。

请注意,这里的“工作集”概念有些主观且具有很高的承重性。通常,内存泄漏是软件仍在考虑其工作集的某些部分而用户不再考虑的问题。

【讨论】:

  • 您错过了这样一个事实,即(来自)小程序的代码实际上通常被打包并作为另一个程序中的可调用函数重用。在这种情况下,分配的存储在小程序的程序终止时没有被释放,这证明了在更大的程序中内存消耗不断增长的原因。在这种情况下,您给出的两个定义是等价的——只适用于不同上下文中的相同代码。
  • @Peter:我没有“错过”它;相反,我们对此事有不同的看法。特别是,孤立的“代码”没有或没有内存泄漏; 程序可以。当然,代码可能会在不将内存泄漏引入程序的情况下以任何实际方式使用它,但实际情况通常不是那么简单。
  • @Peter:我添加了一个具体的例子,说明为什么分配和永不释放的能力很重要。
【解决方案2】:

内存泄漏是指程序分配内存,在不再使用时不释放它,并且丢失其地址(值malloccallocrealloc 返回的指针)。

由于指针丢失,内存不能再被释放,并且会一直连接到程序直到它退出。

如果程序退出,与它相关的所有内存都会被操作系统回收(除了本问题范围之外的极少数情况),因此内存泄漏没有任何后果。

如果程序执行很长时间,可能直到系统关闭,附加到程序的未使用的内存块不能用于其他目的。如果这样浪费的内存量很小,也不会产生任何后果。

相反,如果程序不断分配更多内存而不释放它,系统将耗尽内存供程序使用,并返回NULL 以获得分配请求,或者变得不稳定,因为它使用虚拟内存来兑现请求以牺牲其他程序为代价,并以对存储设备或其他压缩技术的冗长交换操作为代价。在某些时候,系统可能会随机终止进程以尝试恢复可用内存。

这样的内存泄漏是有问题的,必须避免。它们在库函数中尤其成问题,这些库函数可用于运行扩展会话的程序,例如网络浏览器、电子邮件阅读器、文件管理器、媒体播放器、程序管理器......

与其他编程语言不同,C 没有嵌入式垃圾收集器来确定哪些已分配的内存块仍在使用中,因此程序员有责任跟踪所有已分配的块并尽快释放它们。 valgrind 等高级工具可用于验证在程序退出时是否已释放所有分配的块。虽然没有必要在退出时释放内存,但这是一种良好的编程习惯,也是一种确定所有分配的内存块是否已被占用的好方法。

【讨论】:

    【解决方案3】:

    该标准根本不需要内存泄漏。因此,就其本身而言,没有任何情况可以保证内存泄漏。

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

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

    【讨论】:

    • 您似乎将“内存泄漏”定义为“内存仍由不再存在的进程分配”。只是注意到这一点,因为那不是我以前见过的。
    【解决方案4】:

    答案可能取决于malloc 的实现,但通常有两种情况malloc 预计不会产生内存泄漏:

    1. 当您将 0 作为 size 参数传递时,某些实现将只返回 NULL 并且不分配任何内容,而其他实现将返回一个唯一指针,即使这算作分配的零字节,您也会泄漏大约 64记账记录中的字节数。

    2. 发生内存不足时。查看全局变量errno 以获得特定值,通常是ENOMEM 以查看它是否失败。在这种情况下,mallocreturns NULL 也是如此。

    【讨论】:

    • 3.当您定义内存泄漏以排除有意保留到程序结束的良性内存分配时。 +1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    • 1970-01-01
    • 2022-11-04
    • 2012-11-18
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    相关资源
    最近更新 更多