我在 ARC 中遇到了对象生命周期的奇怪行为。我已将范围缩小到以下示例:
//---------------------------------------------------------------------------------
@interface MyObject : NSObject
@end
@implementation MyObject
-(id)init
{
self = [super init];
if(!self) return nil;
NSLog(@" MyObject init %p", self);
return self;
}
-(void)dealloc
{
NSLog(@" MyObject dealloc %p", self);
}
@end
//---------------------------------------------------------------------------------
@implementation TLAppDelegate
-(MyObject *)createMyObject:(NSString *)unusedArg
{
return [MyObject new];
}
-(void)someOperation
{
NSLog(@" Entering someOperation");
MyObject* x = [self createMyObject:@"some message"];
NSLog(@" Exiting someOperation; x should be deallocated right after this...");
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSLog(@"entering applicationDidFinishLaunching");
[self someOperation];
[self someOperation];
NSLog(@"exiting applicationDidFinishLaunching");
}
@end
代码摘要:applicationDidFinishLaunching
来电 someOperation
连续两次。 someOperation
创建一个本地对象,该对象
我期望在 someOperation
时被释放返回。
因此,这是我期望的输出:
entering applicationDidFinishLaunching
Entering someOperation
MyObject init 0x600000012cd0
Exiting someOperation; x should be deallocated right after this...
MyObject dealloc 0x600000012cd0
Entering someOperation
MyObject init 0x600000012cb0
Exiting someOperation; x should be deallocated right after this...
MyObject dealloc 0x600000012cb0
exiting applicationDidFinishLaunching
但这是我实际得到的输出:
entering applicationDidFinishLaunching
Entering someOperation
MyObject init 0x600000012cd0 <-- this object is retained until the end of the output!
Exiting someOperation; x should be deallocated right after this...
Entering someOperation
MyObject init 0x600000012cb0
Exiting someOperation; x should be deallocated right after this...
MyObject dealloc 0x600000012cb0
exiting applicationDidFinishLaunching
MyObject dealloc 0x600000012cd0
为什么第一个对象一直保留到 applicationDidFinishLaunching
返回?
据我所知,没有MyObject
实例应该位于 someOperation
之外。
这不是泄漏,因为它在下一个作用域中被释放。
感觉几乎就像编译器内联 someOperation
,将作用域与调用者合并。但这也不是真的,因为
(如果我错了,请纠正我),编译器无法内联 Objective-C 方法。
对于我的实际项目,这会在多个方面引起问题。首先在我们的日志记录类中,我们跟踪一些范围,但由于这种行为,以下日志:
Generating some list {
Calculating item #1 {
}
Calculating item #2 {
}
Calculating item #3 {
}
}
变成这样,毫无意义:
Generating some list {
Calculating item #1 {
Calculating item #2 {
Calculating item #3 {
}
}
}
}
此外,这意味着我们无缘无故地保留了太多的内存。
有没有办法让这种行为更加可预测?
请注意,如果我使用 __attribute__((objc_precise_lifetime))
,此行为不会改变;它不会改变观察到的行为。
最佳答案
MyObject
不会在 someOperation
结束时释放,因为 createMyObject
返回的对象被保留(创建时)并且自动释放(返回时)。
因此,虽然 someOperation
随后将该对象分配给 x
并按照您的预期保留和释放它,但仍然存在来自 createMyObject
的自动释放引用> 在自动释放池耗尽之前不会被清除(这通常发生在每个运行循环结束时)。
如果您不是从 createMyObject
获取 MyObject
,而是直接实例化它,如下所示:
-(void)someOperation{
NSLog(@" Entering someOperation");
MyObject* x = [[MyObject alloc] init];
NSLog(@" Exiting someOperation; x should be deallocated right after this...");
}
不会出现自动释放的引用挂起,所有内容都应该按照您的预期立即释放。
更新
Martin R 提出了有关 ARC 和命名约定的好观点。默认情况下,方法返回的对象由 ARC 保留/自动释放(如果不保留,则会立即dealloc
)。如果不自动释放,则会泄漏)。
根据 Cocoa 命名约定,有一些方法预计会返回一个“保留”对象,即保留计数为 +1 的非自动释放对象。对于这些特定方法,其名称以 alloc...
、copy...
、init...
、mutableCopy...
开头,或new...
,ARC将返回一个保留的对象。其他一切都会返回一个自动释放的。
关于objective-c - ARC 中奇怪的对象生命周期 : how to force precise object lifetimes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21437807/