ios - 为什么在没有 @autoreleasepool 的 for 循环的每个循环中 NSString autorelease

标签 ios objective-c

这是我的测试代码:

for (int i = 0; i < 1000000000; ++i) {
    NSString *string = @"Abc";
    string = [string lowercaseString];
    string = [string stringByAppendingString:@"xyz"];
}

在ARC环境中,循环不会使内存爆炸。在我的例子中,运行这个循环只需要1.2MB RAM。

但是在MRC中,除非使用@autoreleasepool代码块,否则循环会使内存爆炸。令我困惑的是有很多文章说当代码在for中时需要将代码放在@autoreleasepool中环形。但在这种情况下,没有@autoreleasepool 也没关系。请帮我解决这个问题。谢谢。

更新: 如果我这样写代码:

for (int i = 0; i < 1000000000; ++i) {
    NSString *string = [NSString stringWithFormat:@"aaaaaaaaaaaaaaaaaaa"];
}

这段代码会导致 ARC 和 MRC 中的内存爆炸。为什么?

stringWithFormat:

还返回一个自动释放对象。我对此感到困惑...

最佳答案

使用 ARC 编译的代码必须与未使用 ARC 编译的代码进行互操作。此外,您不能假设 Foundation,尤其是您正在调用的 NSString 的方法,是用 ARC 编译的。

那些 NSString 方法必须以这样的方式编译,以便它们可以从 ARC 和非 ARC 代码中调用。这意味着他们必须自动释放他们返回的对象,无论他们自己是否使用 ARC 编译。

但是,如果那些 NSString 方法是用 ARC 编译的,那么它们可能会使用 objc_autoreleaseReturnValue() 来执行自动释放。如果调用者也是用 ARC 编译的并且它保留了对象(因为,例如,它被分配给了一个强局部变量),那么它可能会对其使用 objc_retainAutoreleasedReturnValue()。在那种情况下,可以避免使用自动释放池。 objc_autoreleaseReturnValue() 通过检查堆栈和调用者的指令,可以检测到调用者将对返回值使用 objc_retainAutoreleasedReturnValue(),它不会自动释放该值,并且它将通过侧 channel 将这一事实传达给 objc_retainAutoreleasedReturnValue(),这样它就不会保留该值。

因此,在某些您不能依靠自己决定的特定情况下,“通常”会自动释放然后保留对象的代码不会。它只会转移所有权。

ARC 不会自动耗尽自动释放池或引入内部自动释放池。

由于不确定性,您应该始终使用 @autoreleasepool 围绕任何可能由于自动释放对象而导致内存激增的代码。例如:

for (int i = 0; i < 1000000000; ++i) @autoreleasepool {
    NSString *string = @"Abc";
    string = [string lowercaseString];
    string = [string stringByAppendingString:@"xyz"];
}

关于ios - 为什么在没有 @autoreleasepool 的 for 循环的每个循环中 NSString autorelease,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33642853/

相关文章:

ios - Collection View 高度

objective-c - MFMessageComposeViewController 中的界面语言

ios - 如何使用自动布局正确约束 UITableView

android - 使用 kivy 在 Android 和 IOS 中播放音频(mp3)

iOS - NSJSONSerialization 抛出一些非常奇怪的错误

ios - 更改 spritekit swift 3 中的初始场景

ios - 拒绝视频通话后弹出视频通话?

objective-c - 是可变类 "heavier?"

ios - 如何实例化(附加) Storyboard并将其推送到我的应用程序中?

ios - 使用带有 dispatch_async 的 block