ARC和在方法中创建的释放对象 [英] ARC and releasing object created in method
问题描述
我偶然发现了一个在其他地方找不到答案的问题.当我调用一个返回指向对象的指针的方法时,该对象后来被使用并且最后设置为nil,它仍然在内存中分配(根据Instruments).我正在使用XCode 4.6.3和iOS 6.1. ARC已打开.
I have stumbled upon an issue for which I can't find answer elsewhere. When I am calling a method which returns pointer to an object which is later used and at the end set to nil, it is still allocated in memory (according to Instruments). I'm using XCode 4.6.3 and iOS 6.1. ARC is turned on.
这是示例代码:
ClassA.h
@interface ClassA : NSObject
-(void)runSomething;
@end
ClassA.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
ClassB.h
@interface ClassB : NSObject
@property int number;
-(id)initWithNumber:(int)number;
-(int)getNumber;
@end
ClassB.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,并调用runSomething方法.此示例代码生成了从未从内存中释放创建的对象(ClassB).如果我从
ClassB is created in view controller and method runSomething is called. This sample code produces that created object (ClassB) is never released from memory. If I change code from
ClassB *instance = [self makeClassBWithNumber:counter];
到
ClassB *instance = [[ClassB alloc] initWithNumber:counter];
创建的对象会在每个循环周期中正确释放.这种行为的原因是什么?我在stackoverflow上发现了一些旧的答案,即makeClassBWithNumber
应该返回调用自动释放return [result autorelease]
的结果,但是如果启用了ARC,则无法做到这一点.
created object is properly released in each of loop cycle. What is the reason for such behaviour? I found some old answers here on stackoverflow that makeClassBWithNumber
should return result invoking autorelease return [result autorelease]
, but this can't be done if ARC is enabled.
推荐答案
区别在于+alloc
返回具有+1保留的对象,ARC将在其作用域末尾与发布保持平衡,因此立即解除分配. +make…
返回具有+1保留和匹配的自动释放的对象.自动释放池耗尽后将发送release
消息.由于您处于"true时"循环,因此自动释放池永远不会耗尽,并且会累积内存.
The difference is that +alloc
returns an object with a +1 retain, which ARC will balance with a release at the end of its scope, and so immediately deallocate. +make…
returns an object with a +1 retain and a matching autorelease. The autorelease pool will send a release
message when it drains. Since you stay in loop "while true," the autorelease pool never drains and you accumulate memory.
解决方案是为您的循环提供一个自动释放池:
The solution is to give your loop an autorelease pool:
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
都是不必要的.
This will cause the pool to drain on every iteration. In any case the instance=nil
is unnecessary.
请务必阅读MartinR的答案.它提供了有关实现细节的更多详细信息,尤其是为什么它可能会根据优化级别而有所不同,以及被调用方法是否与调用方法位于同一编译单元(.m文件)中.那只是一个优化细节;您仍然需要将此@autoreleasepool
放入循环中以确保正确性.
Do read MartinR's answer. It gives some more details on the implementation details, and particularly why this may behave differently depending on the optimization level, and whether the called method is in the same compile unit (.m file) as the calling method. That is only an optimization detail; you still need to put this @autoreleasepool
in the loop for correctness.
这篇关于ARC和在方法中创建的释放对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!