首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在XCode 4.5中,确定调用了dealloc的情况下,ARC存在幻影内存泄漏,还是存在工具问题?

在XCode 4.5中,确定调用了dealloc的情况下,ARC存在幻影内存泄漏,还是存在工具问题?
EN

Stack Overflow用户
提问于 2013-01-10 23:54:59
回答 1查看 1.3K关注 0票数 6

前言;这不是一个普遍的“我有一个巨大的应用程序泄漏”的问题。这是一个具体的问题,要么是自动引用计数在一个几乎微不足道的演示应用程序中无法正常工作,要么是一个微妙的代码生成或编译器问题,要么是Instruments中的一个bug。(TLDR:哦。实际上是一个奇怪的小竞争条件)

我被Instruments的"Allocations“列表显示实例泄漏的事实弄糊涂了,然而,我有一个该类的实例,只有一个,并且ARC导致dealloc方法被调用,我知道它被调用,因为当dealloc完成时,有一条NSLog消息被打印出来,但它仍然显示在Instruments中的泄漏列表中。

retainCount从不超过1。它没有被任何人保留,它正在被取消分配,但它看起来像是一个“泄漏”,因为它在仪器的泄漏中显示为一个活动实例。

那件事怎么可能?

我还在用ARC学习Objective-C,所以我想我一定是犯了一个初学者常犯的错误。下面是我唯一的init和对象的dealloc:

代码语言:javascript
复制
- (id) initWithMessage:(NSString*)messageForUser
{
    self = [super init];
    if (self)
    {
        _message = messageForUser;
        NSLog( @"from constructor: %@",_message);
    }
    return self;

}

- (void)dealloc {
    NSLog(@"Goodbye cruel world. One WPMyObject signing off.");
   // [message release]; // ARC forbiddeth thee! Begone release.
    _message = nil;

   // [super dealloc]; // ARC forbiddeth explicit super dealloc
}

为了看看我是否可以,我试着在dealloc方法中调用[super dealloc],然后ARC用一个错误阻塞了你,这很棒,因为它会帮你做到这一点。但是,当我编写自己的init方法时,它不会阻止我。

当我在XCode中使用" run“运行程序时,我得到了”告别残酷世界“的NSLog消息,正如我所希望的那样,当运行dealloc时,我也得到了在运行结束时实例仍然存在的证据,当使用使用内存泄漏模板的仪器分析时:

如果我不使用下面的实例创建代码运行,我只会得到一些标准库malloc泄漏报告,但如果我添加此代码,则会发生所有泄漏:

代码语言:javascript
复制
  WPMyObject * myObject = [[WPMyObject alloc] initWithMessage: @"Hello World!\n" ];

这是我所看到的,我认为我理解的是告诉我WPMyObject的唯一实例正在泄漏:

完整的源代码(一个使用Objective-C和Foundation/Foundation.h的小型Mac命令行应用程序)在BitBucket上。单击this link在浏览器中查看源代码。

M单元在@autoreleasepool {...}上下文语句中运行单个测试对象实例创建:

如果你想在你自己的计算机上看到完全琐碎的代码,就像这样抓取它:

代码语言:javascript
复制
  hg clone https://bitbucket.org/wpostma/objectivecplaymac

更新:您可以通过在结束自动释放池的}之前添加以下代码行来修复“泄漏”(这可能是Instruments中的错误,也可能是clang/llvm编译器的错误,而不是“真正的泄漏”):

代码语言:javascript
复制
  NSLog( @"Reached end of autorelease pool" );

是啊。添加日志消息。“泄漏”消失了。这是Mac 10.7.5上的XCode 4.5.2 (4G2008a),包含工具版本4.5 (内部版本4523)。

Update2:这真的是一个简单的多进程竞争条件。下面的代码看起来是一个合理的Debug-build版本。如果有一种更明确的方式来说“等待Instruments完成我的工作,然后退出main()",这可能是一个很好的未来功能,苹果工程师。PROFILER_SYNC( "MESSAGE“)宏在发布模式下展开为空,但在调试构建中,它会将”消息“发送到分析器...它确实可能非常方便。

代码语言:javascript
复制
int main(int argc, const char * argv[])
{
    // This creates and cleans up an auto-release pool context.
    @autoreleasepool {

        foo(); // Microscopic amounts of debug code you want profiler to analyze go here.

#ifdef DEBUG
        usleep(10000); // race condition prevention in debug builds, so Instruments can finish up.
#endif

    }
#ifdef DEBUG
    usleep(10000); // race condition prevention in debug builds, so Instruments can finish up.
#endif

   return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-01-12 01:13:54

听起来不像是泄漏,而更像是竞争状况。NSLog的写入和程序执行被终止之间的竞争。或者更有可能是缓冲问题,在达到某个阈值之前不会刷新输出。

尝试将sleep(100);放在自动释放池上的闭合花括号之后。或者尝试向dealloc中的日志消息添加更多文本。

如果这不能“修复”它,那么显示反汇编,并查看两个版本的代码之间发生了什么变化。

发生这种情况的原因:出于性能原因,Instruments和NSLog()都被有效地缓冲。它们设计用于相对较长时间运行的流程中,该流程几乎总是具有主事件循环或对dispatch_main()的调用。

这样做是为了尝试并尽量减少对目标应用程序性能的影响,但这可能会导致微基准测试中的怪异,因为在这些基准测试中,进程的生命周期非常短暂。

如果你在一个短暂的过程中有一个最小的测试用例,我建议你用[[NSRunLoop currentLoop] run];来关闭main()。它将永远运行,并为Instruments和/或调试器提供一个可行的运行时。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14261879

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档