【问题标题】:What's the difference between abandoned memory and a memory leak?废弃内存和内存泄漏有什么区别?
【发布时间】:2012-01-12 18:18:14
【问题描述】:

两者完全相同,只是“废弃内存”是指泄漏的整个对象图,而不仅仅是单个对象。对吧?

【问题讨论】:

  • 它们实际上根本不是一回事;泄漏可以很容易地由整个对象图组成。虽然这个问题是从一个错误的前提中提出的,但它既是一个非常真实的问题,而且在我看来,也是一个有趣的问题。
  • 我正要问一个类似的问题。 “废弃的内存”是指无法访问的内存,对吗?
  • 另外,这与 iOS 和 Objective C 有什么关系?
  • 另见here问答从完全不同的角度解决这个问题

标签: objective-c ios memory-management memory-leaks abandoned-memory


【解决方案1】:

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

应用程序的“活动对象图”是可以从应用程序中的各种“根”直接或间接访问的所有分配。 “根”本身就是对对象的实时引用,无论其他任何东西是否显式引用根。

例如,全局变量是根;通过引用一个对象,一个全局变量,根据定义,使该对象成为应用程序活动对象图的一部分。并且,通过暗示,全局变量引用的对象也被认为是活动的;没有泄露。

堆栈也是如此;任何线程的活动堆栈引用的任何对象本身都被认为是活动的。

考虑到这一点,泄漏废弃的内存实际上确实有两个不同的含义。

泄漏

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

即内存无法访问,因此无法再次引用它(除非出现错误)。这是死记忆。

请注意,如果对象 A 指向对象 B,对象 B 指向 A,但活动对象图中没有任何内容指向 A 或 B,则仍然是泄漏。如果 B->A 和 A->B 引用都是保留引用,那么您将获得保留循环和泄漏。

废弃的记忆

在应用的活动对象图中但由于应用逻辑问题而不再可访问的分配被视为已放弃,但没有泄露。

例如,假设您有一个缓存,其条目是从某个 URL 下载的 NSData 的实例,其中该 URL 在 URL 中包含会话 ID(一种常见模式),并且会话 ID + URL 用作在缓存中查找内容的键。现在,假设用户注销,导致会话 ID 被破坏。如果缓存中没有删除特定于该会话 ID 的所有条目,那么所有这些 NSData 对象都将被丢弃,但不会泄露,因为它们仍然可以通过缓存访问。


实际上,在两者之间做出如此强烈的区分几乎没有用处,因为修复需要非常不同的策略。

修复泄漏是要找出额外保留的来源(或者在基于 malloc() 的泄漏的情况下,可能需要插入对 free() 的丢失调用)。由于检测到的泄漏无法从活动对象图中得到,因此修复泄漏真的很简单。

由于几个原因,修复废弃的内存可能相当棘手。

首先,内存仍然可以从活动对象图中访问。因此,根据定义,您的应用程序中存在保持内存活动的算法问题。发现和修复它通常比修复一个漏洞要困难得多,并且可能会造成破坏。

其次,可能存在对废弃分配的非归零非保留弱引用。也就是说,如果你弄清楚了在哪里修剪强引用并使分配实际上消失了,那并不意味着你的工作已经完成;如果还有任何剩余的非归零弱引用,它们现在将是悬空指针和..... BOOM


正如 Amit 所指出的,Heapshot Analysis 非常擅长发现泄漏、废弃内存以及(非常重要的)整体“不希望的内存增长”。

【讨论】:

  • 悬空指针/废弃内存/僵尸都一样吗?我知道zombie is an deallocated object。用你的行话来说,废弃的记忆似乎不一样
  • @Honey Abandoned 内存不会被释放。这些对象仍然连接到应用程序正在使用的内存,但不再有用。考虑;您的应用程序会进行大量计算并将结果数据缓存在某处——也许是一个全局可变字典——然后您的应用程序会丢失该缓存条目的密钥,再也不会查找它。那是被遗弃的记忆;这些对象存在,消耗内存,可能还有 CPU,但它们对您的应用程序没有任何用处。事实上,这是一种损害。
  • 你能看看 developer.apple.com/videos/play/wwdc2012/242/?time=1850 我了解泄漏与废弃内存的区别。但我认为你所说的“废弃内存”就是苹果所说的“缓存内存”。被遗弃的内存更多是由'root path' 引用的对象,例如runloop 的重复计时器引用或 GCD 引用的 dispatchWorkItem。 (1/2)
  • 或者,废弃的内存是我所说的关于根路径 + 你所说的,因为我们没有它的 sessionID,我们不再可以访问该对象,但仍然可以在实时对象图。 Apple 所描述的缓存内存是您仍然可以引用但只是忘记修剪的对象,例如您可以删除不再出现在屏幕上的项目的图像(2/2)
  • FWIW 你的 sessionID 示例,你可以在会话结束时修剪所有内容 - 不知道 sessionID 吗?或者您是否假设即使在注销后您也希望将某些内容保留在缓存中? (3/2)
【解决方案2】:

不确定是否有标准术语,但也有可能有内存,它确实有参考,但永远不会被使用。 (Leaks 工具的 Heap Shot 功能可以帮助追踪这一点。)我称其为“膨胀”以将其与真正的泄漏区分开来。两者都是浪费内存。

【讨论】:

    【解决方案3】:

    废弃的内存是内存泄漏。 Heapshot Analysis 将帮助您发现不希望的内存增长。这是一篇很好的文章。 http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/

    【讨论】:

    • 被遗弃的记忆不是泄漏。他们所做的就是让我们的内存占用量增加,以存储我们不再需要的东西。
    猜你喜欢
    • 2012-09-21
    • 2012-02-29
    • 2011-01-07
    • 1970-01-01
    • 2011-03-05
    • 2013-03-19
    • 1970-01-01
    • 2011-10-25
    相关资源
    最近更新 更多