【问题标题】:Why this doesn't crash? [duplicate]为什么这不会崩溃? [复制]
【发布时间】:2013-07-01 14:05:39
【问题描述】:

为什么循环中的第二行(a.retainCount 行)不会崩溃(由于访问错误)?

NSArray* a0 = @[[NSMutableString stringWithString:@"a"]];    
NSArray * arr = [NSArray arrayWithObject:a0];
[a0 release];[a0 release];

for (NSArray* a in arr)
{
    //NSLog(@"%d", (a == a0) );
    NSLog(@"RC: %d", a.retainCount);
}

但如果循环中的第一行 (a == a0 one) 未注释,则会崩溃。

当自动释放池耗尽时,这肯定会崩溃,但我特别询问循环中的第二行,而不是之后。

谁能解释一下?

【问题讨论】:

  • 你能解释一下这和xcode有什么关系吗?
  • 这是一道作业题吗?我们不是来帮你做作业的。
  • 其实一开始我还以为这是个愚蠢的问题,但越看越觉得可能不是。
  • @Sohaib 在 Google 上快速搜索“Objective-C autorelease release not crash”会出现欺骗链接作为第一个点击,不要告诉我你做过研究在发布之前,因为你显然没有。
  • @GradyPlayer 那些方便的方法都返回自动释放的对象,所以这一个骗子。

标签: ios objective-c crash exc-bad-access


【解决方案1】:

请查看http://www.whentouseretaincount.com/

向已释放的对象发送消息是未定义的行为。它可能会崩溃,也可能不会。

在这种情况下,它不会崩溃,因为包含该对象的内存还没有被其他东西覆盖。如果你打开 Malloc Scribble,它会崩溃。对NSLog() 的调用巧合会导致内存被乱写,从而导致崩溃。

retainCount 永远不能完全返回 0,因为消息传递释放的对象是未定义的行为。系统不会费心将 RC 减至 0,因为无论如何该对象不再可行。

我很好奇这个问题是在什么背景下提出的?您使用的是使用retainCount 的教程或课程资料吗?


这并不总是分段错误,原因与运行时不会将保留计数减为 0 的原因相同;效率。

要使其成为有保证的分段错误,将意味着浪费几个周期将虚假值写入内存(或减少保留计数)。

事实上,free() 只是将内存标记为可用于将来的malloc()s。它不会以任何方式修改内存的内容,因此未定义的行为

【讨论】:

  • +1,我很高兴有人制作了那个网站......但我认为 OP 可能在隔离错误的同时开始弄乱保留计数(让他们受益于怀疑。)跨度>
  • 哦,当然——每个人在对环境不熟悉时(有时在他们不那么新时)至少会走上 RC 路径。这并没有错,理解它为什么如此无用提供了许多普遍适用于 iOS/Cocoa 开发其他方面的切题信息。
  • @bbum:打印保留计数并不是我真正感兴趣的事情。真正的兴趣是它为什么没有崩溃。也许是因为我的理论是,一旦对象的保留计数达到 0,它的内存就会被发送回系统,然后调用它的方法 should 崩溃(特别是在被调用的方法使用某个实例变量的情况下)。
  • @bbum:为什么向释放的实例发送消息是未定义的行为?
  • @Sohaib:这是未定义的行为,因为根据 C 规范访问已释放的内存是未定义的行为,并且每条消息发送都必须至少访问接收者地址的第一个单词。
【解决方案2】:

这可能随时崩溃。循环中的第一行很可能触发了分配给其他用途的悬空指针“a”处的内存。因此,当第二行引用“a”时,任何事情都可能发生。 如果在“Scheme -> Diagnostics -> Memory Management”中打开 XCode 选项,这可能会立即崩溃。

【讨论】:

  • 是的。实际上 any NSLog 调用而不是 DLog(@"%d", (a == a0) ) 会导致下一条语句崩溃。
  • @Sohaib:我的意思是:即使NSLog(@"%d", 42) 也会导致下一行崩溃。 NSLog 调用会导致已释放实例的内存被覆盖。
  • @Sohaib:没有retainCount为0的对象。如果retainCount为1的对象被释放,则该对象被释放,可能使用free()或类似的东西。这只是意味着以前被对象占用的内存现在可以再次用于将来的分配。但是除非将内存页还给系统,否则内存仍然存在并且可以访问。
  • @MartinR 你应该发布一个答案,因为你是正确的,我已经验证了。
  • @Sohaib:在对象被释放后向其发送消息是未定义的行为,因此当您在对象被释放后向其发送消息时,对象“应该”不会返回任何值。这有点像问“交响乐应该是什么味道?”你无法闻到交响乐的味道,也无法向已释放的对象发送消息。尝试做任何一个都会产生不可预知的结果。
猜你喜欢
  • 2011-06-11
  • 2011-08-04
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
  • 2022-01-13
  • 2018-10-28
  • 2020-10-30
相关资源
最近更新 更多