objective-c - 跟踪所有 Objective-C 的 alloc/allocWithZone/dealloc

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

抱歉描述太长,但是问题并不那么容易......

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

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

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

我使用的主要 Hook 技术:

  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");
    }
   }
  }
  • 这样的代码用于 Hook alloc 方法,并将 dealloc 作为 NSObject 类别方法。
<小时/>

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

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

从概念上讲,一切都很好。

如果需要,我什至可以通过一些规范化函数检测类何时是类集群的一部分(例如 NSString、NSPathStore2;NSDate、__NSCFDate)...(但这对于下面描述的问题并不重要)。

但是这种技术有一些问题:

  • 并不是所有的类都能被捕获,因为 例如,[NSDate date] 没有捕获 在 alloc/allocWithZone 中:但是,我可以在 GDB 中看到 alloc 调用
  • 由于我尝试使用自动单例检测技术(基于retainCount readind)来自动从最终统计中排除某些对象,因此在启动完整的Cocoa应用程序时,NSLocale创建会卡住在预初始化阶段(实际上,即使是简单的Objective-包含 Foundation 框架的 C 命令行实用程序在 main() 之前有一些额外的初始化) - 通过 GDB,有 allocWithZone:一个接一个地调用,....
<小时/>

完整的概念项目草案来源已上传至此处:http://unclemif.com/external/DILeak.zip (3.5 KB)

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

<小时/>

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

第二个问题:为什么 Hook allocWithZone:在某些类的 CFGetRetainCount (或 [inst keepCount])中卡住...

最佳答案

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

你让这条路变得比需要的更加困难。绝对没有必要推出自己的对象跟踪工具(尽管这是一项有趣的智力练习)。

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

在 GC 下,泄漏将采取以下两种形式之一:要么存在对早就应该被销毁的对象的强引用,要么该对象已被 CFRetain 处理而没有平衡 CFRelease

收藏家非常善于弄清楚为什么任何给定的元素仍然不受欢迎。

因此,您需要找到一些停留时间过长的对象。任何物体都可以。一旦获得了该对象的地址,您就可以使用 Instruments 中的对象图工具来找出它为何保留下来;找出仍然引用它的内容或保留它的位置。

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

<小时/>

哦,没有GC,呵呵...

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

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

或者使用 ObjectAlloc 工具。

无论如何,您都需要识别一两个正在泄漏的对象。这样,您就可以弄清楚它上面挂着什么。在非 GC 中,这完全是弄清楚为什么存在保留而不是通过释放来平衡的情况。

关于objective-c - 跟踪所有 Objective-C 的 alloc/allocWithZone/dealloc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1967622/

相关文章:

objective-c - 我可以在 Objective-C 中内联静态类方法吗?

ios - 如何在 CoreData 中使用 NSPredicate 进行排序和限制?

ios - 删除动态添加的文本字段 IOS

objective-c - 如何以编程方式添加可滚动的 NSTableView

C++:读取另一个进程的内存

C++ 程序使用的内存比系统上可用的内存多?

ios - 点击时选择/取消选择 UIButton

xcode - 何时在 Swift 中初始化委托(delegate)

cocoa - 全屏狮子复合动画

iphone - 从后台返回后,iOS应用程序因内存警告而崩溃,但之前没有?