废弃内存和内存泄漏有什么区别?

13

这两种情况其实是一样的,只不过"abandoned memory"指的是整个对象图泄露,而不是单个对象。对吧?


2
它们实际上完全不是同一件事;泄漏很容易由整个对象图组成。虽然问题基于错误前提,但它既是一个非常真实的问题,也是一个有趣的问题,在我看来。 - bbum
我正想问一个类似的问题。你所说的“abandoned memory”是指无法访问的内存,对吗? - JMCF125
此外,这与iOS和Objective-C有什么关系? - JMCF125
还可以查看这里。该问题和答案从完全不同的角度来解决这个问题。 - mfaani
3个回答

29

首先,您需要了解“内存对象图”或“应用程序对象图”(或者只是分配缓冲区时适用的“对象图”)的概念。在这种情况下,“对象”指的是应用程序中的任何分配,无论是对象还是简单的malloc()缓冲区。如果一个对象可以包含对其他对象的引用 - 一个指针-则它被视为“图形”部分。

应用程序的“活动对象图”是从应用程序中的各种“根”直接或间接访问的所有分配。 “根”指的是一些东西,独立地表示对一个对象的实时引用,而不管是否有其他东西显式地引用该根。

例如,全局变量是根;通过引用对象,全局变量,根据定义,使该对象成为应用程序的 活动对象图的一部分。因此,也会考虑任何由全局变量所引用的对象;没有泄漏。

栈也是一样;任何线程的活动堆栈引用的任何对象本身都被视为活动对象。

有了这个想法,泄漏遗弃的内存实际上有两个不同的含义。

泄漏

泄漏是指存在于应用程序的活动对象图中没有对分配的任何引用的内存块

即该内存不可访问,因此除非有错误,否则永远无法再次引用它。这是无用的内存。

请注意,如果对象A指向对象B,而对象B指向A,但是活动对象图中没有任何内容指向A或B,则仍然会发生泄漏。如果B->A和A->B引用都是保留引用,则会产生保留周期和泄漏。

遗弃的内存

因应用程序逻辑问题不再可到达而在应用程序的实时对象图中的分配被视为废弃的,但并非泄漏。

例如,假设您有一个缓存,其中条目是从某个包含会话 ID 的 URL 下载的 NSData 实例(这是一种常见模式),该会话 ID + URL 用作查找缓存中的内容的键。现在,假设用户退出登录,导致会话 ID 被销毁。如果缓存也没有删除与该会话 ID 特定相关的所有条目,则所有这些 NSData 对象将被废弃,但尚未泄漏,因为它们仍然可以通过缓存访问。


实际上,除了修复方法不同外,对于两者之间进行如此强烈的区分几乎没有任何用处。

修复泄漏是找出额外保留的来源(或在基于malloc()泄漏的情况下需要插入free()调用的位置)。由于检测到的泄漏无法从实时对象图中访问,因此修复泄漏确实很简单。

修复废弃内存可能会更加棘手,原因有几个。

首先,内存仍然可以从实时对象图中访问。因此,根据定义,您的应用程序存在算法问题导致内存保持活动状态。查找和修复这些问题通常比修复泄漏要困难得多,并且可能会带来潜在的破坏性。

其次,废弃的分配可能具有非零弱引用而无需保留。也就是说,如果您找到了需要修剪强引用并使分配实际消失的位置,则这并不意味着您的工作已完成;如果还有任何剩余的非零弱引用,它们现在将成为悬空指针,......BOOM


如Amit所说,Heapshot分析非常擅长查找泄漏、废弃内存,以及非常重要的“不良内存增长”。

悬空指针、废弃内存和僵尸对象是一样的吗?我知道zombie是一个已释放的对象。在你们的行话中,废弃内存似乎有所不同。 - mfaani
1
@Honey:被遗弃的内存没有被释放。对象仍然连接到应用程序正在使用的内存,但不再有用。考虑一下:您的应用程序执行一堆计算并将结果数据缓存到某个地方——可能是全局可变字典——然后您的应用程序丢失了该缓存条目的键,永远不会再次查找它。这就是被遗弃的内存;对象存在,占用内存和可能的CPU,但对您的应用程序没有任何用处。实际上是一种损害。 - bbum
你能看一下developer.apple.com/videos/play/wwdc2012/242/?time=1850吗?我理解泄漏和废弃内存的区别。但我认为你所描述的“废弃内存”是苹果所描述的“缓存内存”。废弃内存更多地是指对象被“根路径”(例如由runloop引用的重复计时器引用或由GCD引用的dispatchWorkItem)引用。(1/2) - mfaani
或者说,我所说的关于根路径的废弃内存和你所说的意义相同,即对象不再对我们可用,因为我们没有它的sessionID,但仍然可以在实时对象图中访问。苹果所描述的缓存内存是您仍然可以引用但只是忘记修剪的对象,例如,您可以删除屏幕上不存在的项目的图像(2/2)。 - mfaani
就你提到的sessionID的例子而言,不知道sessionID的情况下,你能否只剪切掉会话结束时的所有内容呢?或者你假设即使在注销后,仍然有一些东西你希望保留在缓存中?(3/2) - mfaani

3

不确定是否有标准术语,但也有可能存在具有引用但永远不会使用的内存。(Leaks工具的Heap Shot功能可以帮助跟踪此问题。)我称之为“膨胀”,以区别于真正的泄漏。两者都是浪费的内存。


1

被遗忘的记忆并不是泄漏。它们所做的是让我们的内存占用增加,而这些记忆已经不再需要了。 - mfaani

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