【问题标题】:Is there a way to "find mystery retains" ...?有没有办法“找到神秘保留”......?
【发布时间】:2011-08-01 01:05:04
【问题描述】:

最近我在修复某人的代码。有一个大类不会解除分配。您必须发布 5 或 6 个版本才能释放它。

我仔细翻遍了大类,最终找到了各种需要发布的东西。

这让我想到:必须有一些非常简单的方法来“找到”对象上的所有保留 ..我说的对吗?

那么,有没有一种简单的方法来“查找所有保留” 对象? XCode 或 Instruments 中是否有其他人都知道的按钮?

当你找不到这样的谜团时,你会怎么做?

所以在 iOS 世界中,如果有人知道 “显示该对象上所有保留的来源” 按钮 - 谢谢!

附注请注意,没有泄漏,而且这个问题与泄漏完全无关。对象只是“完全正确”不会释放。


稍后..

Fabio 真正令人惊叹的解决方案:

Fabio 为这个问题提供了一个惊人的解决方案。九个字,就是:

-(id)retain
    {
    NSLog(@"%@", [NSThread callStackSymbols]);
    return ([super retain]);
    }

这在许多情况下都非常有用,并导致许多其他有用的事情。法比奥,你每年可能永远为我节省了两个人周的工作时间。谢谢!

顺便说一句,如果您刚刚开始掌握这一点并在输出中苦苦挣扎,我发现通常会有很多块具有“UINib instantiateWithOwner:”。看起来那些会先出现,重要的部分会紧随其后。

【问题讨论】:

  • 当然CADisplayLink 会保留对象。 The documentation says so:“新建的展示链接保留了目标。”要使保留消失,您必须 invalidate CADisplayLink
  • 有趣、重要的问题 (+1)。最好的是第一句话;-)
  • 这在 ARC 下不起作用。你不能调用[super retain]。
  • "在 ARC 环境中,您需要先将 -fno-objc-arc 添加到编译器标志,以允许您覆盖保留并调用 super"

标签: iphone memory-management xcode4 retain


【解决方案1】:

仪器可以为您的应用中每个 malloc、释放和保留的任何 Obj-C 对象显示调用堆栈无需更改代码。它在您使用 ARC 时有效,不是 fabio 的解决方案的情况。

这对于寻找那些神秘的东西非常有用 - 例如。当一个对象不应该在它应该释放的时候释放。

方法如下:

  • CMD + I(产品/资料)
  • 当仪器弹出时选择“分配”(不是泄漏)
  • 您的应用应该可以运行了。
  • 尽一切可能让你的谜团继续发生。
  • 选择左侧面板上的“分配”工具。
  • CMD + 1 或选择右侧带有波浪的圆圈。在右下角的面板中,勾选“记录引用计数”选项。这很重要,否则只会记录 malloc 和 frees。
  • 在列表右上角的搜索框中,输入您的班级名称(例如 BCMyObject)。
  • 这会过滤“统计”列表,以显示当前有多少类实例处于活动状态。 #Persistent 列显示有多少实例处于活动状态。
  • 单击该行,然后单击类名旁边的小箭头 ->。您会看到面包屑显示“统计信息 > 分配摘要 > BCMyobject”
  • 这会向您显示该类的所有实例(以及哪些是活动的)。
  • 选择一个实例,然后再次单击箭头(这次按地址)
  • 现在您将在面包屑中看到“统计信息 > 分配摘要 > BCMyObject > 历史记录:0xADDRESS”。
  • 每次对象被 malloc 保留或释放时都会列出。
  • 现在在“记录引用计数”选项所在的左侧面板中,按看起来像条形且连接有框的图标或按 CMD + 3 .
  • 选择其中一行,您将看到导致调用的完整调用堆栈

简单! (什)

【讨论】:

  • 是的,这是正确的答案。有时,覆盖“保留”也是一种解决方案(尽管可能有点“hacky”),但它不适用于 ARC。而这个仪器工具 - 可以。
  • 感谢您的回答 - 我知道您可以使用 Leaks 工具自动获取此信息,但我无法弄清楚如何使用分配工具获取它,因为默认情况下它只显示 malloc。跨度>
  • 先生,您救了我的命,我现在永远感激您为保护我的理智所做的贡献。
  • @BenClayton 我想知道的是,为什么我们不能用 Leaks 工具检测到那些而不是检查分配?仪器是否出现故障?编辑:我正在尝试过滤掉在应用程序结束时不会发布的实例。检查分配是一种选择,但它们不会在泄漏工具中显示为泄漏。
  • @mostruash 应用程序结束时没有泄漏之类的东西。如果应用程序关闭,它分配的所有内容都会被释放。不管它之前是否发布过。
【解决方案2】:

只是猜测...但是您可能会覆盖调用 super 的自定义类的 retain 方法并抛出一个漂亮的 NSLog 来打印调用堆栈。


用 Joe 的实际代码更新

-(id) retain {
NSLog(@"%@", [NSThread callStackSymbols]);
return ([super retain]);
}

另一个重要的细节是 [NSThread callStackSymbols] 返回一个 NSArray 的 NSStrings 可以被过滤并用于其他目的。例如在复杂和动态的代码中,检查一个方法是否正确地导致另一个方法触发。

注意: 在 ARC 环境中,您需要首先将 -fno-objc-arc 添加到编译器标志中,以允许您覆盖保留并调用 super。

【讨论】:

  • 我认为问题是你想要这个保留的调用者,所以基本上是调用堆栈中的一帧。
  • @Joe 这应该可以工作 NSLog(@"%@", [NSThread callStackSymbols])。 @Gorilla我喜欢你的回答:更好,因为你看到Xcode很好地压缩了堆栈。巧妙的解决方案!
  • @Joe callStackSymbols 是我在 Stack Overflow 中发现的一个巧妙的技巧(我认为)。不幸的是,我无法找到原始答案。很高兴你喜欢这个解决方案!!!
  • 这在 ARC 下不起作用。你不能调用[super retain]。
  • 真棒格雷格,谢谢 - 我想知道 ARC 的“等效”是什么?也许只是返回超级。
【解决方案3】:

不幸的是,以编程方式确定对象“拥有”对象并不容易,因为“对象所有权”的概念是一种编码约定(除非您启用垃圾收集)。

堆栈日志记录通常很有用(我通常在bt;continue 中使用一些断点),但这只会告诉您调用保留的函数,而不是“更大的图景”(例如,您可能会使用[ivar2 release]; ivar2 = ivar1; ivar1 = nil;“转移所有权”) .有时它是 UIKit 泄漏,所以你没有源代码,你真的必须去挖掘。

但是,如果不是泄漏,请致电 -release 几次,看看它在哪里崩溃!

【讨论】:

    【解决方案4】:

    在自定义类的保留上放置断点

    您可以在保留上设置一个符号断点,然后将其设置为自定义类的保留方法。这里的问题是,retain 是NSObject 上的一个方法,所以在放置断点时,您将获得所有objective-c 类的选择。

    在这种情况下,最好通过调用 super 覆盖自定义类的 retain 方法,这样它不会做任何事情,但您可以在其中放置一个断点。

    使用断点动作记录调用者

    要添加断点操作,请双击蓝色标记。在列表中找到断点,然后按右侧的 + 按钮。然后选择Debugger command并在此字段中添加GDB命令frame 1,它将显示保留的调用者。通过这个你冷日志所有保留以及它们来自哪里。以类似方式记录发布时,您可以检查额外发布的内容。

    还是有点乏味,但这是我能想到的最好的了。

    【讨论】:

    • 嗯。我不知道这是否是一个普遍的问题。有时可以使用一些 Objective-C 运行时魔法来找出问题,但我看不出如何追溯函数调用。
    • 我以前做过这个,当时我很好奇是什么保留了我的一个对象。我创建了一个自定义子类,覆盖了-retain,只是让它调用[super retain]。如果您在对 super 的调用上放置断点,则每次触发时都可以轻松查看堆栈跟踪以查看谁负责。对于更频繁的保留/释放事件,您甚至可以在使用应用程序时使用音频断点来听到这些事件。
    【解决方案5】:

    仪器及其内存管理的东西是你的朋友。泄漏和僵尸是可用的两个最有价值的工具。使用它们。

    产品 -> 配置文件(或 Cmd-I)

    【讨论】:

    • @Joe 有很多资源可用于学习如何使用 Instruments。从查找 WWDC 视频开始。至于覆盖-retain,可能会起作用,但感觉不对。
    • 所以,如果你让这个对象泄漏,Instruments 将显示该对象的所有保留。
    • 这个问题与泄漏绝对没有关系,或泄漏仪器。干杯。
    【解决方案6】:

    您是否尝试过在 Xcode 中使用“构建和分析”?

    这对于获取未释放对象的底部非常有用。

    【讨论】:

      猜你喜欢
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 2018-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多