我正在学习ARC内存管理,并遇到了对我没有意义的事情。
在下面的示例代码中,在main()中本地分配的对象在其指针被指定为nil时会被释放,正如我所期望的那样。
但是如果在另一个函数中分配了相同类型的对象,并且在main()中定义了指向它的指针,并且该指针设置为nil,则在main函数退出之前不会释放该对象。这对我来说很神秘。
在下面的代码中,创建了两个类GRMemoryChecker实例。在一种情况下,它直接在main()中分配,而在另一种情况下,main()调用itemMakerFunc()来进行分配。运行main()时,日志输出显示当函数指针设置为nil时,函数中分配的实例不会被释放 - 当函数退出时,它将被释放。
我认为这意味着itemMakerFunc()创建的实例在指针设置为nil之前有2个所有者,而本地创建的实例只有1个。
但为什么呢?当指针设置为nil时,还存在哪个其他所有者?或者如果没有其他所有者仍然存在,为什么计数器在它不存在时会减少呢?
GRMemoryChecker.h:
#import <Foundation/Foundation.h>
@interface GRMemoryChecker : NSObject
{
NSString *name;
}
- (id)initWithName:(NSString *)str;
- (void)setName:(NSString *)str;
- (void) dealloc;
@end
GRMemoryChecker.m:
#import "GRMemoryChecker.h"
@implementation GRMemoryChecker
- (id)initWithName:(NSString *)str
{
self = [super init];
if (self)
{
[self setName:str];
}
return self;
}
- (void)setName:(NSString *)str
{
name = str;
}
- (NSString *)description
{
return name;
}
- (void) dealloc;
{
NSLog(@"Destroyed: %@", self);
}
@end
的main.m:
#import <Foundation/Foundation.h>
#import "GRMemoryChecker.h"
GRMemoryChecker *itemMakerFunc()
{
return [[GRMemoryChecker alloc] initWithName:@"func-based checker" ];
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
GRMemoryChecker *checkerLocallyCreated = [[GRMemoryChecker alloc] initWithName:@"locally-created checker"];
GRMemoryChecker *checkerFuncBased = itemMakerFunc();
NSLog(@"Before setting func-based checker pointer to nil");
checkerFuncBased = nil;
NSLog(@"After setting func-based checker pointer to nil");
NSLog(@"Before setting locally-created checker pointer to nil");
checkerLocallyCreated = nil;
NSLog(@"After setting locally-created checker pointer to nil");
}
return 0;
}
控制台输出:
Before setting func-based checker pointer to nil
After setting func-based checker pointer to nil
Before setting locally-created checker pointer to nil
Destroyed: locally-created checker
After setting locally-created checker pointer to nil
Destroyed: func-based checker
答案 0 :(得分:4)
它不依赖于对象是否在函数中创建,而是依赖于 函数具有&#34;保留的返回值&#34;或者“未获得的返回值”#34; (见Objective-C Automatic Reference Counting)。
默认情况下,alloc
,copy
,init
,mutableCopy
和new
个系列中仅包含方法
保留了返回值,这意味着该函数返回一个(+1)保留对象。
所有其他功能都有一个未保留的返回值。你可以说,简化一些事情 这些函数返回一个自动释放的值(取决于优化 由ARC编译器制作)以确保返回值在调用函数中有效。
当前自动释放池被销毁时,将释放自动释放的值。
您可以使用NS_RETURNS_RETAINED
属性更改函数的行为:
GRMemoryChecker *itemMakerFunc() NS_RETURNS_RETAINED;
GRMemoryChecker *itemMakerFunc()
{
return [[GRMemoryChecker alloc] initWithName:@"func-based checker" ];
}
现在该函数返回一个保留值,该值已取消分配
通过设置checkerFuncBased = nil
:
Before setting func-based checker pointer to nil Destroyed: func-based checker After setting func-based checker pointer to nil Before setting locally-created checker pointer to nil Destroyed: locally-created checker After setting locally-created checker pointer to nil
答案 1 :(得分:3)
当您手动保留和释放对象时,ARC会强制执行您应遵循的相同内存管理语义。那么让我们看看我们如何在MRR下编写这个,看看它是否能告诉我们什么:
GRMemoryChecker *itemMakerFunc()
{
return [[[GRMemoryChecker alloc] initWithName:@"func-based checker" ] autorelease];
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
GRMemoryChecker *checkerLocallyCreated = [[GRMemoryChecker alloc] initWithName:@"locally-created checker"];
GRMemoryChecker *checkerFuncBased = itemMakerFunc();
NSLog(@"Before setting func-based checker pointer to nil");
checkerFuncBased = nil;
NSLog(@"After setting func-based checker pointer to nil");
NSLog(@"Before setting locally-created checker pointer to nil");
[checkerLocallyCreated release];
checkerLocallyCreated = nil;
NSLog(@"After setting locally-created checker pointer to nil");
}
return 0;
}
基本上,alloc
返回的引用是一个拥有引用,需要释放。当一个对象只存在于一个函数中时,我们可以直接释放它,它将立即被释放。但是当我们从函数返回它时,我们不能简单地释放它,因为它需要经过return语句,因此它会被自动释放。
答案 2 :(得分:0)
首先,你的dealloc方法正在泄漏。你必须在其中调用[super dealloc],否则永远不会释放对象。
关于两个实例的不同行为,当您在itemMakerFunc中返回已分配的对象时,ARC将在返回时应用“autorelease”。因此,该实例是自动释放的,但在其他固定器发布时不会立即释放。另一方面,保留另一个实例,然后在将nil赋值给变量时立即释放。认为autorelease是一个后置动作。它将在当前循环结束时释放,但不会立即释放。