如何判断对象何时发送消息?

时间:2009-06-03 17:20:35

标签: iphone objective-c cocoa-touch

我正在处理一个有点棘手的iPhone崩溃,看起来罪魁祸首是NSString被过早释放。我已经打开了NSZombiesEnabled并且可以看到NSString在崩溃时是一个僵尸。但是,我无法确定对象何时被释放/解除分配 - 我已经通过我的代码查找了发送到此对象的释放消息,并在这些位置设置了断点,但它们没有被击中。 / p>

我认为这可能是一个线程或自动释放问题,因为它是间歇性的,但有没有办法通过Xcode调试器挂钩到objective-c运行时来告诉对象被释放的确切位置?或者有更好的方法来诊断这个问题吗?

5 个答案:

答案 0 :(得分:5)

如果您可以在模拟器中重现崩溃,您可能希望查看使用malloc_history工具。 (它有一个手册页。)你需要设置一些环境变量:我通常通过Arguments窗格中的“Edit Active Executable”屏幕设置它们,然后使用那里的复选框启用/禁用它们。确保在设备上进行调试之前禁用它们;如果启用,程序将尝试写入沙箱不允许的/tmp

我发现这个工具与NSZombie结合使我可以跟踪alloc / premature-release / access-after-dealloc错误。在NSZombie报告对已释放对象的访问权限后,您可以使用malloc_history计算分配对象的时间。这通常会让我走上解决问题所在的道路。

我发现另一个非常宝贵的工具是来自LLVM项目的 clang 。它仍处于开发阶段,但它们经常为MacOS-X生成对我来说非常稳定的二进制文件。特别是,它了解Cocoa内存管理策略。使用它就像:

% cd ${DIRECTORY_CONTAINING_XCODE_PROJECT}
% xcodebuild clean
% scan-build -V xcodebuild

这将完整构建您的项目并生成一份报告,列出该工具发现的任何明显错误(包括参考计数搞砸)。

答案 1 :(得分:4)

我可能不会直接思考,但你考虑过在课堂上添加一个发行版和dealloc

- (void) release 
{
  NSLog(@"Releasing");
  [super release];
}
- (void) dealloc
{
  NSLog(@"Deallocating");
  [super dealloc];
}

将Ben Gotow的评论纳入使用obj-c类别,你最终得到了这个:

@interface NSString (release) 
  -(void) release;
@end

@implementation NSString (release)
-(void) release
{
  NSLog(@"NSString Released!");
  [super release];
}
@end

答案 2 :(得分:2)

你可以告诉objc dtrace提供商在调用-[NSString release]时触发你的调查,但这会涉及一些讨厌的hackery。 NSStrings实际上不是NSStrings,但它们都是子类,因为类被实现为类集群的方式。现在,这不会妨碍我们; NSString没有自己的-release :-)。不过,您可以提供自己的类别。

或者,如果您很容易确定哪个NSString实例会中断,则可以在-[NSObject dealloc]上使用self==myInstance设置条件断点。

答案 3 :(得分:2)

另一种方法。确保打开NSZombie,以便报告获得额外版本的对象的内存地址。然后使用Performance Tool-> Object Allocations运行。这将带来乐器。查看Xcode管理器提供的控制台日志。一旦你得到崩溃查找仪器中的内存地址。您将在该对象上看到mallocs / frees的完整历史记录,以及直接链接到代码中的链接。

答案 4 :(得分:0)

你能实现dealloc()并在那里放一个断点吗?从那一点看堆栈跟踪应该告诉你它在何处以及如何被释放。