是否必须释放每个malloc调用

时间:2010-12-02 19:45:30

标签: c pointers malloc

根据我的理解,因为malloc动态分配mem,你需要释放该mem以便它可以再次使用。

  1. 如果你返回一个使用malloc创建的char *会发生什么(即你应该如何释放它)
  2. 如果你保持指针原样 并退出应用程序 (我无法找到答案,有些人说是,有些人说不。)

9 个答案:

答案 0 :(得分:7)

  1. 如果你有一个指向由malloc创建的内存的指针,那么使用该指针free该内存将做正确的事情。是的,有一些魔法涉及;这将由您的编译器处理。

  2. 是的,如果忽略内存释放并退出应用程序,操作系统将释放内存。然而,将其视为不一致被认为是不好的做法。操作系统可能无法做正确的事情(特别是在嵌入式设置中),或者可能无法及时完成。此外,如果您持续运行程序,最终可能会消耗越来越多的内存,最终消耗掉所有内存,并耗尽内存并崩溃。

答案 1 :(得分:7)

  1. 来电者必须释放它(或安排将其释放)。这意味着创建和返回资源的函数需要准确记录它应该如何被释放。

  2. 当程序退出时,大多数操作系统将释放内存,作为“进程”定义的一部分。 C标准并不关心会发生什么,它超出了程序的范围。并非所有操作系统都具有完整的流程抽象,但桌面式操作系统肯定会这样做。

  3. 在此之前释放它的主要原因是:

    • 如果您尽快释放内存,通常在流程退出前很长一段时间,您的程序总共使用较少的内存。
    • 如果你没有释放它,并且你以后想要将程序更改为另一个程序中的例程,这可能被多次调用,那么突然间你需要的内存比以前多很多(内存泄漏)。< / LI>
    • 通过警告您在程序退出时仍然分配的内存,有一些调试工具可以帮助您识别内存泄漏。如果有很多故意泄露的垃圾可以通过,这些并没有多大帮助。
    • 如果你没有释放它并且你遇到任何问题,那么以后回去并找到所有需要释放的内存要比在一开始就做的更难。
    • 在很多情况下你需要释放内存(以防止在长时间运行的程序中使用大量内存),你的默认策略必须是清理几乎所有内容。

    不可自由的含糊不清的理由是:

    • 少量代码。
    • 如果您在程序退出之前就有多个块可以单独释放,那么让操作系统放弃整个过程可能要快得多。
    • 如果您不确切知道它的使用位置,那么按需创建并存储在全局中的东西可能很难安全清理。想想你在进行时填充的某种缓存,可能有MRU规则来限制它占用的内存量,因此它不是无限制的泄漏。好的,所以这是一件坏事(不受限制的全局变量)导致另一件坏事(不同意的内存),但值得了解的原因是你可能会在现有代码中看到不一致的块,而你不一定只是进入并修复它们。

    解放的原因几乎总是超过反对的理由。

答案 2 :(得分:4)

是。如果你是malloc,你需要免费。如果您没有空闲,则可以在程序运行时保证内存泄漏。

释放它。

始终

周期。

答案 3 :(得分:2)

是的,每次拨打malloc()都必须与拨打free()进行匹配。

回答您的具体问题:

  1. 您必须明确记录您的API,告诉用户返回的指针是否必须为free()'d
  2. 操作系统将释放分配给该进程的所有内存。

答案 4 :(得分:2)

如果您自己编写函数:避免这样做。

  • 相反,让调用者传递一个缓冲区,让调用者指定缓冲区的大小并将数据复制到该缓冲区中。这样,您可以使用其他不使用相同堆的模块中的函数(其他编程语言,不同的C运行时...)
  • 如果由于某种原因无法使用这样的接口,请在函数文档中指定调用者在完成后必须释放返回的指针。

如果您使用的是库函数:请查看文档。

  • 如果文档说明您必须免费,请执行此操作。
  • 如果文档说明您不需要,则可能需要调用一些全局清理函数来释放模块的资源。

关于你的第二个问题,建议在退出前释放。从技术上讲它不会受到伤害,但是当你想要在一个更大的项目中重用你的代码时,你会感谢你首先编写了正确的清理。

答案 5 :(得分:1)

C标准没有单个程序执行之外的系统环境概念,因此它无法指定“程序退出后”发生的情况。同时,在调用malloc或从free返回之前,没有任何地方要求使用exit获取的内存应该或必须与main一起发布,而且我认为很明显,目的是在没有手动释放内存的情况下退出不会让资源受阻 - 就像调用exit而不关闭所有文件一样会自动关闭它们(包括刷新它们)。

现在,至于你 是否不应该致电free,这在很大程度上取决于您的特定计划。

  • 任何库代码都应free尽快为内部使用而获得的任何内存。
  • 将分配的对象返回给调用程序的库应始终提供相应的调用以释放这些对象。
  • 作为全局初始化的一部分执行任何分配的库(注意:这是一个非常糟糕的设计,但有时是不可避免的)应该为应用程序提供一种方法来反转初始化并释放所有已分配的内容。如果可能动态加载库(即使满足另一个动态加载库的依赖项的结果),这一点尤其重要。

到目前为止,我只讨论过图书馆代码。此时,剩下的就是应用程序本身或库代表应用程序进行的分配。我认为,我承认这是非正统的,释放这些物品不仅是不必要的,而且是有害的。我说这个的主要原因是大多数长期存在的应用程序将累积相当多的分配内存,而这些内存并没有被大量使用(想想字处理器中的撤消缓冲区或浏览器中的历史记录)。在适度加载的系统上,大部分数据在应用程序终止时已交换到磁盘。如果你想要释放它,你将最终走遍所有已交换的内存地址,追踪所有指向免费的指针,

  • 对硬盘的物理组件进行无用的磨损
  • 让用户等待您的应用程序退出
  • 导致其他仍在使用的应用程序数据被换出,使它们运行得更慢

所有这一切都以荒谬的名义“你必须释放你所分配的一切”的规则。

对于短期应用程序来说,它并不是一件大事,但是你可以经常简化执行单个线性任务的短期应用程序的实现,如果你不打扰释放他们分配的所有内存,你就可以退出。想想大多数unix命令行实用程序。在退出之前,为sed编写循环以释放所有已编译的正则表达式是否有用?程序员的时间不能用在更有效率的事情上吗?

答案 6 :(得分:0)

1)与正常释放内存的方式相同,即

p = func();
//...
free(p);

诀窍是确保你总是这样做......

2)一般来说,是的。但你仍然应该释放你使用的任何记忆作为良好的做法。不花时间弄清楚释放内存的地方只是懒惰。

答案 7 :(得分:0)

让我们一次抓住这一点......

  1. 如果您返回char *,而您知道该malloc是使用free(myCharPtr)创建的,那么是的,您有责任将其释放。您可以使用{{1}}。

  2. 执行此操作
  3. 操作系统将恢复内存,并且它不会永远丢失,但从技术上讲,无法保证在应用程序终止时它将被收回。这取决于操作系统。

答案 8 :(得分:0)

我不会说每个malloc必须被释放,但我会说,无论程序运行多长时间,都必须有一定数量的分配(和总大小)被释放。该数字不必是静态常量,但必须根据其他内容来指定(例如,此程序处理小部件;它将为最大小部件中的每个quizzix分配一个64字节结构)。人们可能事先不知道最大小部件的大小,但是,例如,一个人知道处理小部件所需的临时存储量与其大小的平方成正比,人们可以安全地推断出最大的小部件将足够小,以至于搁置的内存总量将非常小。