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

时间:2009-12-28 01:14:37

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

很抱歉有很长的描述,但问题并不那么容易......

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

序言:标准仪器和Omni泄漏检查器由于某种原因不适合我(Omin Tool拒绝我的应用程序,Instruments.app(Leaks)吃太多内存和CPU因此我没有机会使用它。)< / p>

所以我想编写并使用我自己的代码来钩住&amp;跟踪“all”alloc / allocWithZone:/ dealloc messages statistics编写一些简单的自己的泄漏检查库(主要目标只是标记对象的类名和可能的泄漏)。

我使用的主要挂钩技术:

  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然后注册&amp;计算所有alloc / allocWithZone:调用increment(+1)stat-array NSInteger值,dealloc调用as decrement(-1)。

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

在概念上一切正常。

如果需要,我甚至可以检测类何时是类集群的一部分(如NSString,NSPathStore2; NSDate,__ NSCFDate)......通过一些normalize-function(但对于下面描述的问题无关紧要)。

然而,这种技术存在一些问题:

  • 并非所有课程都可以被捕获 例如,[NSDate date]无法捕获 在alloc / allocWithZone中:但是,我可以在GDB中看到alloc调用
  • 由于我正在尝试使用自动单例检测技术(基于retainCount readind)从最终统计信息中自动排除某些对象,因此在启动完整Cocoa应用程序时,NSLocale创建会在pre-init阶段冻结(实际上,甚至是简单的Objective-包含Foundation框架的C命令行实用程序在main()之前有一些额外的初始化 - 由GDB有allocWithZone:一个接一个地调用,....

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

Terminal.app 运行 make 进行编译,运行 ./ concept 以显示其效果。


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

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

3 个答案:

答案 0 :(得分:6)

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

你正在以这种方式努力。完全没有必要推出自己的对象跟踪工具(尽管这是一项有趣的心理练习)。

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

在GC下,泄漏将采取两种形式之一;要么强烈引用该对象应该很久以前被销毁该对象已CFRetain'而没有平衡CFRelease

收藏家非常擅长弄清楚为什么任何特定物品都不受欢迎。

因此,您需要找到一些粘贴太久的对象。任何对象都可以。获得所述对象的地址后,您可以使用“仪器”中的“对象图形”仪器来确定其粘附的原因;找出仍在提及它或保留它的地方。

或者,从gdb中,使用info gc-roots 0xaddr查找生成对象的所有各种事物。如果打开malloc历史记录(请参阅malloc手册页),则可以获取保存引用的对象的分配历史记录。


哦,没有GC,呵呵......

你仍然需要大量工具,无需重新发明轮子。

leaks命令行工具通常会为您提供一些好的线索。打开MallocStackLoggingNoCompact以使用malloc_history(另一个命令行工具)。

或使用ObjectAlloc工具。

在任何情况下,您都需要识别一个或两个被泄露的对象。有了它,你可以弄清楚它上面挂着什么。在非GC中,这完全是一个弄清楚为什么保留不能通过发布平衡的情况。

答案 1 :(得分:4)

即使没有泄漏仪器,仪器仍然可以帮助您。

从Leaks模板开始,然后从中删除Leaks仪器(因为你说它使用了太多的内存)。单独的ObjectAlloc将告诉您所有对象的分配和释放,以及(在Leaks模板中默认情况下启用了一个选项)所有的保留和释放。

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

This video may help.

答案 2 :(得分:-2)

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