使用 operator new/malloc 分配的内存块能否在程序执行结束后持续存在? [复制]

Posted

技术标签:

【中文标题】使用 operator new/malloc 分配的内存块能否在程序执行结束后持续存在? [复制]【英文标题】:Can a memory block allocated by using operator new/malloc persist beyond end of program execution? [duplicate] 【发布时间】:2012-07-08 03:55:53 【问题描述】:

可能重复:When you exit a C application, is the malloc-ed memory automatically freed?

当我阅读有关在 C/C++ 中的动态内存分配方面分别使用 delete/free 的强制性时,我想到了这个问题。我想如果内存分配在我的程序执行终止之后仍然存在,那么是的,它是强制性的;否则,我为什么要担心释放分配的空间?操作系统不会在进程终止时自动释放它吗?我有多正确? 我的问题是可以

int *ip = new int(8);

在我的程序终止后仍然存在?

【问题讨论】:

进程终止时释放,但循环尝试。 【参考方案1】:

简短回答:不。

长答案:不。C++ 永远不会持久化内存,除非你努力让它这样做。释放内存的原因是这样的:

如果你不释放内存,而是继续分配它,你会在某个时候用完。一旦你用完了,几乎任何事情都可能发生。在 Linux 上,也许 OOM 杀手被激活并且您的进程被杀死。也许操作系统将您完全分页到磁盘。如果您使用足够的内存,也许您会给 Windows 盒子一个蓝屏。它几乎可以被认为是未定义的行为。此外,如果您泄漏内存,它只是坐在那里,未使用,未释放,并且在您的进程终止之前没有人可以使用它。

还有另一个原因。当您向分配器释放内存时,分配器可能会保留它,但只需将其标记为可用。这意味着下次你需要记忆时,它已经在那里等着你了。这意味着更少调用内核来请求内存,从而提高性能,因为上下文切换非常低效。

编辑:C 和 C++ 标准甚至不保证在终止后操作系统会清理内存。许多操作系统和编译器可能,但不能保证。尽管如此,所有主要的桌面和移动操作系统(可能是 DOS 和一些非常古老的嵌入式系统除外)都会在它之后清理进程内存。

【讨论】:

这个答案非常以 Linux 为中心。我完全不确定 language 能保证这种行为。 @unwind:不,语言没有。我会编辑。我知道它以 Linux 为中心,但我知道的是 Linux。 @unwind:虽然确实如此,但在其他系统下并没有太大的不同(当然,很少有系统一开始就拥有如此可憎的 OOM 杀手)。大约 20 年前,这在“家用计算机”上可能有所不同,但在当今的每个主流操作系统(以及过去 40-45 年的每个专业操作系统)上,当一个进程终止时,它的所有内存页面都会立即“噗” ”。因此,尽管语言不能保证它,但它仍然可靠地发生。请注意,我并不是说依赖它就很好...... @Damon:为什么你会说 OOM 杀死一个可憎的东西?当系统真正内存不足(不再物理,不再交换)时,系统必须做某事,不是吗?为什么杀死有问题的进程是一件坏事?只要可以对其进行配置,以使您的任务关键型服务器进程不再需要。 它没有被“修复”,因为当父进程使用大量内存时,它显然会破坏fork()/exec() 的组合:quora.com/…【参考方案2】:

您不需要在程序退出之前将内存释放回操作系统,因为操作系统会在进程终止时回收已分配给您的进程的所有内存。如果您分配一个直到您的过程完成为止所需的对象,您不必释放它。

话虽如此,释放内存仍然是一个好主意:如果您的程序大量使用动态内存,您几乎肯定需要运行内存分析器来检查内存泄漏。分析器会告诉你最后没有释放的块,你需要记住忽略它们。将泄漏次数保持为零会好得多,原因与消除 100% 编译器警告的好处相同。

【讨论】:

不仅如此,释放内存也是至关重要的。您认为当您的后台守护程序每小时多占用 500 MB 的 RAM 时,客户/用户会很高兴? 哦!我知道了。对不起......我以为你会扔掉指针并让操作系统在最后得到它。我的错! +1!【参考方案3】:

1) 当您请求时释放您的内存(如果不在堆中)。内存泄漏从来都不是一件好事。如果它现在不伤害你,它可能会在路上。

2) C 或 C++ 不保证您的操作系统会为您清理内存。有一天,您可能会在一个实际上没有的系统上进行编程。或者更糟的是,您可能正在将不关心内存泄漏的代码移植到这个新平台。

【讨论】:

任何没有清理此内存的操作系统都是垃圾。这意味着该操作系统上的任何应用程序崩溃都会永远留下这些泄露的资源。标准 malloc/new 创建应用程序内存,没有理由相信它会在应用程序结束后持续存在。 如果它不清理内存,我不会称它为操作系统。那时它只是一个设备抽象层。 @edA-qa mort-ora-y 好的。对于这样的系统,您个人选择什么词并不重要,不是吗?那好吧。生活还在继续。【参考方案4】:

作为一个历史记录:旧 Amiga 计算机(“AmigaOS”)使用的操作系统没有像现在假设的那样具有完整的内存管理(除了可能在 Amiga 不再流行时发布的一些更高版本)。

CPU 没有 MMU(内存管理单元),因此每个进程都可以访问所有物理内存。因为当两个进程想要共享一些信息时,他们可以交换指针。操作系统甚至鼓励这种做法,它在其消息传递方案中使用了这种技术。

但是,这使得无法跟踪哪个进程拥有哪一部分内存。因此,操作系统没有释放已完成进程的内存(或任何其他资源,事实上)。因此,释放所有分配的内存至关重要。

【讨论】:

【参考方案5】:

任何好的操作系统都应该在进程退出时清理所有资源; “总是释放你分配的东西”的原则有两个好处:

    如果您的程序泄漏内存但从未退出(守护程序、服务器等),持续泄漏内存将严重浪费 RAM。

    您不应该推迟释放所有内存,直到您的程序终止(就像 Firefox 有时那样 - 注意到它需要多长时间才能退出?) - 关键是最小化您分配内存的时间;即使您的程序继续运行,您也应该在完成后立即释放分配的 RAM。

【讨论】:

@SanJacinto:尽管现在任何主要的内核都会在您将系统从内存不足的灾难中拯救出来之后清理您的内存。 NT 会,Mach/XNU 会,Linux 会,BSD 会,等等。 好的,您考虑过多少实时和轻量级操作系统?我知道这是司空见惯的行为,这就是让事情变得更糟的原因。如果你一直认为“所有好的”操作系统都会这样做,那么总有一天会有人大吃一惊。 @SanJacinto:我知道。但我只考虑 99% 的具有真正处理能力的设备使用的主要内核。其中大多数是 DOS(我不知道)、Linux(肯定会)、OSX 的 Mach/XNU(肯定会)、Windows NT(会)或其他 UNIX(很可能会)。 @SanJacinto 你认为我建议不要自己清理吗?我没有。我刚刚告诉过我希望一个像样的操作系统在进程退出时进行清理 - 以防程序员不小心忘记这样做。 好吧,你的猜测是错误的——我使用过很多这些嵌入式操作系统——但我认为它们在这里有点超出范围,因为我认为 OP 主要考虑的不是特殊的嵌入式系统,专有系统,或任何“异国情调”的东西——从他的个人资料来看,我认为他只想了解好的 ol' PC。尽管您在技术上是正确的,但我觉得这次谈话现在变得更像是一个毫无意义的争论,我不想开始拖钓。【参考方案6】:

如果您非常确定您将永远需要在程序的生命周期内释放内存,从技术上讲,跳过释放/删除可能没问题。 Linux、Windows 等操作系统将在进程结束时释放分配的内存。但在实践中,您几乎永远不能假设您分配的内存不需要在进程的生命周期内释放。牢记代码的可重用性、可维护性和可扩展性,最好始终在适当的位置释放您分配的所有内容。

【讨论】:

没错。因为想象一个系统是否处于高负载状态?不释放内存的程序将导致代价高昂的上下文切换和内存丢失。除非您正在编写特殊的任务关键型软件,该软件将是唯一运行的软件,并且无法承受使用malloc free(但使用低级技术)的性能影响,然后你可以考虑不释放。【参考方案7】:

这是一个有趣的问题。我最初对您的问题的看法是您是否可以在程序完成后访问内存,但在第二次阅读之后,我发现您想知道为什么应该释放内存。

您释放动态分配的内存,因为如果您不这样做,操作系统和其他进程将耗尽,您将不得不重新启动。

我认为您可能希望在程序完成后访问该内存,所以我的猜测是,即使您将动态分配的内存块的起始地址和长度写到控制台或文件中,该地址也可能程序完成后无效。

那是因为当你的程序运行时,你有一个虚拟页面地址,在程序完成后,如果没有内核权限,你可能无法访问该地址。或者,还有其他原因。

【讨论】:

【参考方案8】:

它肯定不会在程序终止之后继续存在。这个想法是在不再需要时释放内存,这样您的程序就不会浪费内存(它不会消耗超过它真正需要的内存),或者更糟糕的是,不会耗尽内存(取决于您的分配模式)

【讨论】:

【参考方案9】:

您必须担心它,因为假设您在很多地方分配了大量内存而不是释放它。一旦分配了内存,它就会占用一部分无法再分配的内存。这将导致可用内存量每次都变得越来越小,因为您无法释放它。在某些时候,内存将被耗尽。即使内存在程序终止时被释放,想象你的程序一次运行几个星期,不断地分配内存但从不释放它。内存是一种有限的资源,使用动态分配时你需要负责。

【讨论】:

以上是关于使用 operator new/malloc 分配的内存块能否在程序执行结束后持续存在? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

new/malloc的差别

C++内存分配秘籍—new,malloc,GlobalAlloc详解

new,malloc,GlobalAlloc具体解释

new &&delete

new/delete

new/delete