我正在处理一个有点棘手的iPhone崩溃,看起来罪魁祸首是NSString被过早释放。我已经打开了NSZombiesEnabled并且可以看到NSString在崩溃时是一个僵尸。但是,我无法确定对象何时被释放/解除分配 - 我已经通过我的代码查找了发送到此对象的释放消息,并在这些位置设置了断点,但它们没有被击中。 / p>
我认为这可能是一个线程或自动释放问题,因为它是间歇性的,但有没有办法通过Xcode调试器挂钩到objective-c运行时来告诉对象被释放的确切位置?或者有更好的方法来诊断这个问题吗?
答案 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()并在那里放一个断点吗?从那一点看堆栈跟踪应该告诉你它在何处以及如何被释放。