我偶然发现了一个我在其他地方找不到答案的问题。当我调用一个返回指向一个对象的指针的方法时,该对象稍后被使用并在最后设置为 nil,它仍然分配在内存中(根据 Instruments)。我正在使用 XCode 4.6.3 和 iOS 6.1。 ARC 已打开。
示例代码如下:
A类.h
@interface ClassA : NSObject
-(void)runSomething;
@end
A类.m
#import "ClassA.h"
#import "ClassB.h"
@implementation ClassA
-(void)runSomething {
int counter = 0;
while (true) {
ClassB *instance = [self makeClassBWithNumber:counter];
NSLog(@"%d", [instance getNumber]);
[NSThread sleepForTimeInterval:0.01];
instance = nil;
counter++;
}
}
-(ClassB*) makeClassBWithNumber:(int)number {
return [[ClassB alloc] initWithNumber:number];
}
@end
B类.h
@interface ClassB : NSObject
@property int number;
-(id)initWithNumber:(int)number;
-(int)getNumber;
@end
B类.m
#import "ClassB.h"
@implementation ClassB
-(id)initWithNumber:(int)number {
self = [super init];
if(self) {
_number = number;
}
return self;
}
-(int)getNumber {
return [self number];
}
@end
ClassB 在 View Controller 中创建并调用方法 runSomething。此示例代码生成创建的对象 (ClassB) 永远不会从内存中释放。如果我从
更改代码ClassB *instance = [self makeClassBWithNumber:counter];
到
ClassB *instance = [[ClassB alloc] initWithNumber:counter];
创建的对象在每个循环周期中被正确释放。这种行为的原因是什么?我在 stackoverflow 上找到了一些旧答案,makeClassBWithNumber
应该返回结果调用 autorelease return [result autorelease]
,但如果启用了 ARC,则无法完成。
最佳答案
不同之处在于 +alloc
返回一个带有 +1 保留的对象,ARC 将在其范围结束时与释放进行平衡,因此立即释放。 +make ...
返回一个带有 +1 保留和匹配自动释放的对象。自动释放池将在耗尽时发送一条 release
消息。由于您在“为真时”处于循环中,因此自动释放池永远不会耗尽并且您会积累内存。
解决方案是给你的循环一个自动释放池:
while (true) {
@autoreleasepool { // <== Add an autorelease block here.
ClassB *instance = [self makeClassBWithNumber:counter];
//NSLog(@"%d", [instance getNumber]);
NSLog(@"%d", [instance number]); // Fix naming; do not prefix accessors with `get`
[NSThread sleepForTimeInterval:0.01];
// instance = nil; // Does nothing in this loop.
counter++;
}
}
这将导致池在每次迭代时耗尽。在任何情况下,instance=nil
都是不必要的。
编辑:一定要阅读 MartinR 的回答。它提供了有关实现细节的更多详细信息,特别是为什么这可能会因优化级别而有所不同,以及被调用方法是否与调用方法位于同一编译单元(.m 文件)中。那只是一个优化细节;您仍然需要将此 @autoreleasepool
放入循环中以确保正确性。
关于ios - ARC 并释放在方法中创建的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18727445/