【问题标题】:Track all Objective-C's alloc/allocWithZone/dealloc跟踪所有 Objective-C 的 alloc/allocWithZone/dealloc
【发布时间】:2010-12-30 08:54:40
【问题描述】:

对不起,描述太长了,但是问题并不那么容易......

我在没有 GC 的情况下编写的项目。最近我发现了一个我找不到的内存泄漏。我确实使用了新的 Xcode Analyzer,但没有结果。我确实逐行阅读了我的代码并验证了所有 alloc/release/copy/autorelease/mutableCopy/retain 和 pools... - 仍然没有。

前言:由于某种原因,Standard Instruments 和 Omni Leak Checker 对我不起作用(Omin Tool 拒绝了我的应用程序,Instruments.app(Leaks)占用了太多内存和 CPU,所以我没有机会使用它)。

所以我想编写并使用我自己的代码来挂钩和跟踪“所有”alloc/allocWithZone:/dealloc 消息统计信息,以编写一些简单的自己的泄漏检查库(主要目标只是标记可能泄漏的对象的类名)。

我使用的主要挂钩技术:

  Method originalAllocWithZone = class_getClassMethod([NSObject class],@selector(allocWithZone:));
  if (originalAllocWithZone)
  {
   imp_azo = (t_impAZOriginal)method_getImplementation(originalAllocWithZone);
   if (imp_azo)
   {
    Method hookedAllocWithZone = class_getClassMethod([NSObject class],@selector(hookedAllocWithZone:));
    if (hookedAllocWithZone)
    {
     method_setImplementation(originalAllocWithZone,method_getImplementation(hookedAllocWithZone));
     fprintf(stderr,"Leaks Hook: allocWithZone: ; Installed\n");
    }
   }
  }
  • 这样的代码钩住 alloc 方法,和 dealloc 作为 NSObject 类别方法。

我将 IMP 保存为以前的方法实现,然后注册并计算所有 alloc/allocWithZone:调用为增量 (+1) stat-array NSInteger 值,而 dealloc 调用为减量 (-1)。

作为终点,我调用之前的实现和返回值。

在概念上一切正常。

如果需要,我什至可以检测类何时是类集群的一部分(如 NSString、NSPathStore2;NSDate、__NSCFDate)...通过一些规范化功能(但对于下面描述的问题无关紧要)。

但是这种技术存在一些问题:

  • 并非所有类都可以被捕获,因为 例如,[NSDate date] 没有捕捉到 在 alloc/allocWithZone: 但是,我可以在 GDB 中看到 alloc 调用
  • 由于我尝试使用自动单例检测技术(基于retainCount readind)从最终统计信息中自动排除一些对象,当启动完整的Cocoa 应用程序(实际上,即使是简单的Objective-包含 Foundation 框架的 C 命令行实用程序在 main()) 之前有一些额外的初始化 - GDB 有 allocWithZone: 一个接一个地调用,....

在此处上传完整的概念项目草稿源:http://unclemif.com/external/DILeak.zip (3.5 Kb)

Terminal.app 运行 ma​​ke 来编译它,运行 ./concept 来展示它。


第一个问题:为什么我不能通过挂钩 alloc 和 allocWithZone: 方法来捕获所有对象分配?

第二个问题:为什么挂钩 allocWithZone:某些类的 CFGetRetainCount(或 [inst retainCount])冻结...

【问题讨论】:

  • 哇。避免使用明显的解决方案真的很远,因为它们太慢或使用太多内存,但是,有人想知道,当工具(无论您使用哪种工具)不被留下时,任何这样的论点是否有效在最终构建中,但仅在怀疑有问题时使用。我认为对于 99.999% 的人来说,使用标准工具是正确的答案,而使用自己的工具是一个奇怪的解决方案,很少有其他开发人员会觉得有用。

标签: objective-c cocoa memory memory-leaks objective-c++


【解决方案1】:

神圣的重新发明轮子,蝙蝠侠!

你让这种方式变得比它需要的更难。完全没有必要使用自己的对象跟踪工具(尽管这是一种有趣的心理练习)。

因为你使用的是 GC,所以跟踪分配和识别泄漏的工具都非常成熟。

在 GC 下,泄漏将采取以下两种形式之一;要么有一个对早就应该被销毁的对象的强引用或者该对象已经CFRetain'd 没有平衡CFRelease

收藏家非常善于弄清楚为什么任何给定的物品都超出了它的欢迎范围。

因此,您需要找到一些停留时间过长的对象。任何物体都可以。一旦你有了所述对象的地址,你就可以使用 Instruments 中的 Object Graph 工具来找出它为什么会出现;找出仍在引用它的内容或保留它的位置。

或者,从 gdb 中,使用 info gc-roots 0xaddr 来查找使对象成为根的所有各种事物。如果您打开 malloc 历史记录(参见 malloc 手册页),您可以获得持有该引用的对象的分配历史记录。


哦,没有 GC,嗯...

您仍然拥有大量工具,无需重新发明轮子。

leaks 命令行工具通常会给你一些很好的线索。打开 MallocStackLoggingNoCompact 以便能够使用 malloc_history(另一个命令行工具)。

或者使用 ObjectAlloc 工具。

在任何情况下,您都需要识别一个或两个正在泄漏的对象。有了它,你就可以弄清楚它上面挂着的是什么。在非 GC 中,这完全是一个弄清楚为什么它有一个没有被释放平衡的保留的情况。

【讨论】:

  • 他说他是在“没有”GC的情况下写的。然而,对于我们这些使用 GC 编写的人来说,这是一个信息丰富的答案。
  • 不错的提示。谢谢。我尝试了泄漏工具。然而,我的背景目标是编写一些库来自动检查 DEBUG 构建中代码的泄漏,用于单元测试。所以我需要从代码中控制测试点 - 激活一些线程的泄漏捕获,读取 stat... 以使过程自动化......我确实找到了我的泄漏。没有什么神秘的——只是在一个地方错过了自动释放。但是我的两个问题仍然悬而未决。
【解决方案2】:

即使没有 Leaks 工具,Instruments 仍然可以帮助您。

从 Leaks 模板开始,然后从中删除 Leaks 工具(因为您说它占用了太多内存)。单独的 ObjectAlloc 将告诉您所有对象的分配和解除分配,以及(在打开的选项,这是泄漏模板中的默认设置)它们的所有保留和释放。

您可以将 ObjectAlloc 工具设置为仅显示仍然存在的对象;如果您将应用程序带到不应该存在任何对象(或某个类的对象)的地步,并且这些对象仍然存在,那么您就有泄漏。然后,您可以深入查找泄漏的原因。

This video may help.

【讨论】:

  • 谢谢。这种方式是首选,但是,正如我之前所说 - 有时 Instruments 工具会占用太多内存,并且跟踪的 App 确实会变慢......但是通过限制一些输入数据和监控时间 - 有可能与 Instruments 合作。
  • 我现在使用以下解决方案来捕获消耗内存的泄漏:启动 Instruments,打开 Leaks 模板,删除 Object Alloc 轨道,仅运行带有泄漏的应用程序(我也将自动检测时间设置为 30-60 秒价值)。它在跟踪泄漏时提供 10 倍的内存和时间经济性!
  • 很酷的解决方案彼得,这个 Instruments 的东西非常灵活。
【解决方案3】:

从 Xcode 模板开始。在您知道自己在做什么之前,不要尝试为可可应用程序滚动您自己的 main() 例程。

【讨论】:

  • 滚动你自己的 main() 的原因有很多。不过,这不是其中之一。
  • 是的,演示示例不是 Cocoa - 它只是使用 Foundation 框架简化演示的命令行实用程序。 Cocoa 方式和这个简单的 App 的区别在于 main()/NSApplicationMain() 之前的隐藏初始化。尝试在 concept.m 中取消注释 NSLocale 行 - 以查看使用原始 Cocoa 应用程序构建 DILeak 库时会看到的冻结问题。查看 [NSDate date] 以确认它没有被 alloc-tracker 记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-20
  • 2012-01-27
  • 1970-01-01
  • 2013-08-18
  • 1970-01-01
  • 2019-01-13
相关资源
最近更新 更多