ios - XCode 4.5 中 ARC 的 Phantom 内存泄漏,其中肯定调用了 dealloc 或 Instruments 问题?

标签 ios objective-c cocoa automatic-ref-counting instruments

序言;这不是一般性的“我有一个存在泄漏的巨型应用程序”问题。这是一个关于自动引用计数在几乎微不足道的演示应用程序中无法正常工作的特定问题,具有完整的源代码,或者微妙的代码生成或编译器问题,或者 Instruments 中的错误。 (TLDR:哦。实际上是一个奇怪的小竞争条件)

我对 Instruments 的“分配”列表显示实例泄漏这一事实感到困惑,然而,我有该类的一个实例,只有一个,ARC 导致调用 dealloc 方法,我知道它是被调用是因为在 dealloc 完成时打印了一条 NSLog 消息,但它仍然显示在 Instruments 的泄漏列表中。

retainCount 永远不会超过 1。它没有被任何人保留,并且正在被释放,但它看起来像是一个“泄漏”,因为它在 Instrument 的泄漏中显示为一个事件实例。

这怎么可能?

我仍在学习使用 ARC 的 Objective-C,所以我想我一定犯了一个常见的初学者错误。这是我唯一的初始化和对象的 dealloc:

- (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 运行时,我也得到了这个实例仍然存在于运行结束,当使用 Instruments analysis using memory leaks template 时:

如果我在没有下面的实例创建代码的情况下运行,我只会收到一些标准库 malloc 泄漏报告,但如果我添加此代码,所有泄漏都会发生:

  WPMyObject * myObject = [[WPMyObject alloc] initWithMessage: @"Hello World!\n" ];

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

enter image description here

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

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

enter image description here

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

  hg clone https://bitbucket.org/wpostma/objectivecplaymac

更新:您可以通过在 } 结束自动释放池:

  NSLog( @"Reached end of autorelease pool" );

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

更新 2:这确实是一个简单的多进程竞争条件。下面的代码似乎是一个合理的黑客调试构建位。如果有更明确的方式说“等到 Instruments 完成我的工作,然后退出 main()”,这可能是一个不错的 future 功能,Apple 工程师。一个 PROFILER_SYNC("MESSAGE") 宏,它在 Release模式下扩展为空,但在调试版本中,将“MESSAGE”发送到分析器......它确实非常方便。

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;
}

最佳答案

听起来不像泄漏,更像是竞争条件。写入 NSLog 与程序执行终止之间的竞争。或者更有可能是缓冲问题,在达到特定阈值之前不会刷新输出。

尝试在自动释放池的右大括号之后放置一个 sleep(100);。或者尝试在 dealloc 中的日志消息中添加更多文本。

如果这不能“修复”它,则显示反汇编代码并查看两个版本的代码之间有何变化。


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

这样做是为了尽量减少对目标应用程序性能的影响,但它可能会导致微基准测试出现异常,因为该过程的生命周期极短。

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

关于ios - XCode 4.5 中 ARC 的 Phantom 内存泄漏,其中肯定调用了 dealloc 或 Instruments 问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14261879/

相关文章:

objective-c - 计算网页加载到 UIWebView 所需的时间

cocoa - Cocoa中文件拖放的问题

ios - iPhone - 异步 NSURLConnection HTTP 响应可能会干扰正在运行的进程吗?

ios - 点击 UINavigationBar 标题进行更改

ios - NSNotificationCenter postNotificationName 在 swift 和 object-c 中崩溃,为什么?

iphone - 可以部分释放一 block 内存吗?

ios - 如何将 UIView 与从 ViewController 继承的属性或变量一起使用?

Cocoa Dock 触发 NSApplicationDidChangeScreenParametersNotification

ios - 单张 Flickr 照片导致荒谬的容量异常

ios - 使用 parse.com 设置关注者列表的最佳方法是什么