为啥在调试模式和运行模式下保留计数不同?

Posted

技术标签:

【中文标题】为啥在调试模式和运行模式下保留计数不同?【英文标题】:Why retain count is diffrent in debug mode and in running mode?为什么在调试模式和运行模式下保留计数不同? 【发布时间】:2016-05-12 08:49:35 【问题描述】:

我知道 ARC 和 MRC 的工作原理。但是在测试下面的代码时我很困惑。我不知道为什么会这样。为什么同一个问题在调试模式和运行模式下保留计数不同?

    NSMutableArray *a = [NSMutableArray array];
    [a addObject:@"abc"];
    NSLog(@" 1 Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)a));
    __weak  NSMutableArray *b = a;
    NSLog(@" 2 Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)a));
    a = nil;
    NSLog(@" 3 Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)b));
    [b addObject:@"xys"];
    NSLog(@" 4 Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)b));

当我在运行模式下运行应用程序时,应用程序在行 NSLog(@" 3 Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)b)); 上崩溃,我理解为 b 是 a 的 weak 引用。并在将nil 分配给它时反对获取释放。但在此之前,如果显示前两行的输出如下图所示。这也是正确的。

但是当应用程序处于调试模式时(意味着我们已经设置了断点和调试),应用程序没有崩溃,并且在每行显示保留计数 2。如下图。

有人知道为什么会这样吗?为什么相同的代码为不同的模式给出两个不同的保留值?

【问题讨论】:

不要依赖retainCount 做任何事情。尤其是使用 ARC,您无法分辨 retains 和 releases 插入的位置。在发布模式下,优化器会尽量避免无关的retains 和releases,所以你看到的数字通常会不同。 天哪。接力棒! 【参考方案1】:

documentation 中 retainCount 方法的第一句话说:

请勿使用此方法。

后来:

您不太可能从这种方法中获得有用的信息

只是不要使用它。

正如 ***foe 在评论中指出的那样,给定代码中使用的 CFGetRetainCount 有一个类似的(可能稍微少一些)免责声明。

我一直将其理解为“它可能有用,但价值可能不是您认为的那样。不要通过查看绝对值得出任何结论,因为我们可能会做我们想做的每一个魔术有了它,这不关你的事”。

【讨论】:

CFGetRetainCount()(OP实际使用的方法)的文档说“这个函数可能对调试内存泄漏有用。你通常不使用这个函数,否则。”。 是的,我知道我们不应该使用这种方法。但我的观点是这种方法有什么问题。为什么它提供错误的 retainCount ? 应该没有错。但是可能会有比您想象的更多(或更少)的保留或发布。由于编译器所做的优化,它们也可能在不同的时间发生。然后,谁知道调试模式会发生什么变化?但我同意,这种语义变化似乎很奇怪!

以上是关于为啥在调试模式和运行模式下保留计数不同?的主要内容,如果未能解决你的问题,请参考以下文章

为啥发布和调试模式下的代码行为不同?

为啥我的程序在发布模式下运行良好,但在调试模式下失败? [关闭]

Flutter:一个程序在调试模式下运行良好,但在发布后就不行,为啥?

为啥消息处理程序在调试模式下不起作用?

调试和发布模式下Activity的不同菜单项

带有 javascript 调试的 Visual Studio 在直接运行和在调试模式下运行时显示不同的行为