对动态分配的对象不调用 delete 是否始终是内存泄漏?

Is not calling delete on a dynamically allocated object always a memory leak?

提问人:Luchian Grigore 提问时间:3/29/2012 最后编辑:CommunityLuchian Grigore 更新时间:3/29/2012 访问量:742

问:

这里开始的讨论中,我想知道以下代码是否存在内存泄漏:

int main()
{
   new int();
   //or
   int* x = new int();
   return 0;
}

我知道内存作系统回收了,但无论如何都是泄漏吗?我相信是的。

内存泄漏的定义是什么?我只能在标准中找到一个参考,它不是很有帮助。

编辑:我不想开始辩论 - “我认为......”不是我要找的那种答案。我最感兴趣的是来源 - C++书籍或网站或任何关于它的内容。

C++ 管理内存 泄漏

评论

3赞 Some programmer dude 3/29/2012
内存泄漏只是您分配但未释放的内存。
0赞 Luchian Grigore 3/29/2012
@JoachimPileborg这就是我在泄露的讨论中所说的。詹姆斯说这是记忆的逐渐丧失。我找不到任何令人满意的来源。
0赞 stefan bachert 3/29/2012
@Joachim这太简单了。根据您的定义,分配的内存已经是内存泄漏
1赞 James Kanze 3/29/2012
回复编辑:当涉及到一个词的含义时,没有明确的参考,所以“我认为......”或多或少地暗示在任何答案中。关于唯一可以应用的非主观论点涉及拟议定义的有用性,即使这样也不是 100% 客观的。
2赞 Martin York 3/29/2012
无用的讨论。术语“内存泄漏”仅在上下文中才有意义。最一般的含义是动态分配的内存,这些内存已丢失(没有对内存的引用)到执行的应用程序线程,因此无法有效利用。

答:

1赞 stefan bachert 3/29/2012 #1

我会这样定义内存泄漏

a) 它需要内存

b) 它对应用程序不再有用

c) 它不再可访问,因此不再可删除

据此,我会判断您的样本为内存泄漏。 您的样品显示非严重泄漏。 一个严重的泄漏是持续占用内存,在应用程序崩溃之前可能发生什么

4赞 Chris 3/29/2012 #2

上面的代码确实存在泄漏。然而,更重要的是,如果你没有分配一个 ,你分配了一个特殊的对象,比如一个服务器连接对象,如果你从来没有正确地清理和调用,该对象的析构函数永远不会运行,如果你的服务器连接需要执行特殊的清理代码(写入文件等),这可能很重要。intdelete

在您的特定示例中,泄漏无关紧要,因为 main 立即退出(有效)并且内存被释放回操作系统。但是,在编写生产代码时,您绝对不应该留下任何泄漏(即使是像上面这样微不足道的泄漏),因为代码可能会被移动到不同的函数中,并且泄漏实际上可能会在程序生命周期中传播。

此外,也许要考虑的最重要的事情是程序员认为是内存泄漏。您应该将内存视为一种资源,应根据自己的模型进行管理。请考虑阅读本文,其中讨论了一些资源分配和管理模型。考虑 RAII(资源获取即初始化)和智能指针(或者至少是智能指针的概念和引用计数的概念)。

评论

0赞 Chris 3/29/2012
有人想在 -1 上填写我吗?
0赞 Alex Z 3/29/2012
同样在这里。我们最好知道我们的答案出了什么问题,这样我们就可以在答案不准确时删除/编辑它们。
0赞 Luchian Grigore 3/29/2012
没有提到内存泄漏意味着什么。并没有真正回答这个问题。
0赞 Alex Z 3/29/2012
您明确询问“我想知道以下代码是否存在内存泄漏”。虽然我已经删除了我的,因为恕我直言,其他人更好,但我认为这个答案足够相关,不足以证明投反对票是合理的。
-1赞 Sanish 3/29/2012 #3

是的,存在 4 个字节的泄漏,因为分配的内存不是 d,并且在应用程序的生命周期内它是泄漏。newdelete

从这个链接:

http://www.yolinux.com/TUTORIALS/C++MemoryCorruptionAndMemoryLeaks.html

Memory leak description: Memory is allocated but not released causing an application to consume memory reducing the available memory for other applications and eventually causing the system to page virtual memory to the hard drive slowing the application or crashing the application when than the computer memory resource limits are reached. The system may stop working as these limits are approached.

评论

0赞 Luchian Grigore 3/29/2012
但是,这 - “导致应用程序消耗内存,减少其他应用程序的可用内存” - 不适用。
0赞 Sanish 3/29/2012
如果某个应用程序在循环中泄漏内存,并且此应用程序运行的时间较长,则系统速度会变慢。当然,这取决于内存泄漏量。示例中的泄漏不会导致系统速度变慢。
0赞 Sanish 3/29/2012
是的,我知道你的代码中没有循环。我之所以提到循环,是因为在这种情况下,内存泄漏可能会减慢系统速度。
1赞 SigTerm 3/29/2012 #4

这是主观的/值得商榷的。

在我看来,有两个级别的资源(内存是操作系统提供的资源之一)泄漏:操作系统级别和应用程序级别。请注意,名称是自定义的,可能有更合适的技术术语。

一旦应用程序终止,应用程序级泄漏将不复存在,因为操作系统会清理应用程序的混乱。也就是说,一旦应用程序被核弹,对操作系统稳定性的威胁就消失了。在体面的操作系统上,应用程序中的内存分配只能产生“应用程序级”泄漏。

一旦应用程序终止,操作系统级泄漏就不会停止存在。通常,其他一些资源属于该类别(文件),但不属于内存。但是,我不能保证没有操作系统/平台不清理泄漏的内存。根据墨菲定律,即使在今天,也可能有这样的平台在使用。

因此,当我说/写“内存泄漏”时,我说的是应用程序级泄漏 - 任何未被 APP 显式删除的内存分配。每一次分配,即使是有意的,都属于类别。此外,通常内存分配分析器和类似工具会抱怨您的“故意泄漏”,

所以,是的,你的代码有泄漏。

在我看来,即使你确定操作系统会释放它们,即使是故意泄漏也是一个坏主意,因为它鼓励草率的编码,有一天你将无法删除在其析构函数中释放某些东西的类,操作系统无法自动清理。鉴于普通 PC 上 Windows 注册表和临时文件夹中剩余的垃圾数量,许多程序员经常将该技术用于操作系统未正确清理的资源。因此,最好的主意是避免泄漏。

评论

0赞 James Kanze 3/29/2012
如果你谈论的是一般的资源(而不仅仅是内存),那么操作系统无法清理所有内容。您未能删除的临时文件是资源泄漏,操作系统不会清理它。 (至于其余的,您发明了“泄漏”一词的全新且无用的定义。
1赞 Alok Save 3/29/2012 #5

第二种情况不是内存泄漏。
这不是泄漏,因为您仍然有一个指向已分配内存的指针。
为了定义内存泄漏,我想坚持定义大多数内存分析工具(如 valgrind)使用的定义:

内存已分配,随后无法释放,因为程序不再具有指向已分配内存块的任何指针。

评论

1赞 Luchian Grigore 3/29/2012
+1 我有点知道这一点,这就是我发布两个版本的原因。所以第一个是,即使它不是不断泄漏?
2赞 Jesse Good 3/29/2012
+1:一个简短、简洁的定义:objects inaccessible by running code but still stored in memory
0赞 Alok Save 3/29/2012
@LuchianGrigore:我故意克制不对第一种情况发表评论,因为你的问题说,“我认为......不是我要找的那种答案”。好吧,既然你问了,我认为第一种情况是泄漏,我相信 valgrind 同意,但话又说回来,这只是我和 valgrind 的想法,而不是一些标准:)
0赞 James Kanze 3/29/2012
@Als 当他从 返回时,指针就不复存在了,所以这不是一个或另一个方向的争论。main
4赞 Martin York 3/29/2012
我想说第二种情况仍然是泄漏;main() 并不特殊,一旦 main 退出,就不再引用动态分配的内存(所以它已经泄漏了),程序仍在运行,直到它退出操作系统>
5赞 James Kanze 3/29/2012 #6

这取决于您如何定义“泄漏”。根据最明显的 定义,也是唯一有用的定义,它不是泄漏,至少在 应用程序级别。桶不会因为您故意泄漏而泄漏 允许有限量的水逸出。实际上, 应用程序不会因为有意允许绑定集而失败 的对象在程序结束之后持续存在。

关于内存泄漏,我们对这个词的看法是 由“泄漏检查器”着色---如 Purify 或 Valgrind 等程序。他们 作用是找到泄漏(除其他外),但他们没有办法 知道什么是故意的,什么是无意的,什么是有约束力的,以及什么 不是。因此,他们发明了其他定义:无法触及的对象 已经“泄露”(在实际代码中很有可能是 true),或者在执行完所有 静态对象的析构函数已被执行“泄露”。在 后一种情况,定义显然是错误的,而且有点 无用。但是有足够多的情况,这样的事情是泄漏的,它 至少警告它们(“可能的泄漏”)是合理的,前提是 有一种方法可以过滤掉特定情况。(净化和 Valgrind 认识到并非所有这些案例都是真正的泄漏,并且 提供各种过滤机制来检测它们。所有这些 很好,很好——我很高兴我们有这样的工具——但是 我们不应该允许他们歪曲语言。

最后提醒一下:标准说标准 iostream 对象(等)永远不会被破坏。所以任何缓冲区 他们分配将(可能)永远不会被释放。当然没有人在他们的 正确的头脑会考虑这些“泄漏”。std::cout

评论

1赞 Matthieu M. 3/29/2012
这当然是一个有趣的观点,我从未想过有限泄漏的情况,但它确实是有道理的。我感到开悟了。
0赞 James Kanze 3/29/2012
@MatthieuM。从实用的角度来看,“有界性”的问题对我来说似乎很重要。它符合我直觉上认为的非编程环境中的“泄漏”。但是与Merriam-Webster的核对表明,即使在非编程环境中,也不是那么清楚。
0赞 supercat 11/30/2012
术语“泄漏”可以表示编程和非编程上下文中的有界和无界方案。事实上,只有五加仑的液体可以从五加仑桶的孔中逸出,但这并不意味着这个孔不是“泄漏”。如果对象在程序退出后继续无用地存在,它们就会被泄露。另一方面,如果再次运行程序会导致对象被重用,那么它们是可重用的,这意味着它们不是“无用的”。如果操作系统在它们造成问题之前清理它们,它们就不会泄露。