类方法中由alloc引起的内存泄漏?

时间:2014-03-11 22:33:38

标签: objective-c memory-leaks class-method

我发现如果我在Class方法中分配一个新对象并将其返回给main(),那么当我不再需要该对象时,它似乎会导致内存泄漏。

例如,这是一个简单的Class,它包含一个返回其自身实例的Class方法:

@interface Stinker : NSObject
{
    int a;
}
+(instancetype) makeAStink;
-(void) showThem;
-(void) setEm: (int) z;
@end

@implementation Stinker
-(void) showThem
{
    NSLog(@"%d",a);
}

-(void) setEm: (int) z
{
    a = z;
}

-(void) dealloc
{
    NSLog(@"Arrrgggggh!");
}

+(instancetype) makeAStink
{
    id temp = [[self alloc] init];
    return temp;
}
@end

现在,如果我直接从main()创建一个实例:

Stinker *aStink =[[self alloc] init];

然后将aStink设置为nil:

aStink = nil;

调用重写的dealloc方法和Argggggh!消息已记录。这很好并且符合预期。

但是如果我使用我编写的Class方法来创建一个实例:

Stinker *aNewStink = [Stinker makeAStink];

行为不同。

现在,如果我将aNewStink设置为nil,它将不再指向对象但对象未被销毁。不调用dealloc并且不记录Arggggh消息。

似乎它仍然拥有某个所有者。

当然,当main()终止时,对象被销毁并最终调用dealloc。 但这似乎表明,在程序终止之前,未使用和不受欢迎的对象仍然在堆上闲置。

这不是内存泄漏吗? 我应该避免使用Class方法来分配新实例吗?

2 个答案:

答案 0 :(得分:0)

这是您的示例的MRC(没有ARC)代码

+(instancetype) makeAStink
{
    id temp = [[self alloc] init];
    return [temp autorelease];
}

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

id obj = [Stinker makeAStink]; // obj is autoreleased object

id obj2 = [[Stinker alloc] init]; // obj2 is not autoreleased
[obj2 release]; // so you need to release it

[pool release]; // now obj is released and deallocated

所以obj有一个额外的保留计数,将在下一个runloop中释放(和解除分配),而obj2将在调用release时立即释放

这不是内存泄漏,这是通常的行为,并且(通常)不会以明显的方式影响程序性能

答案 1 :(得分:0)

使用ARC时,以下代码

+(instancetype) makeAStink
{
    id temp = [[self alloc] init];
    return temp;
}

与Non-ARC相同:

+(instancetype) makeAStink
{
    id temp = [[self alloc] init];
    return [temp autorelease];
}

感谢自动释放,aNewStink = nil将使newNewStink在下一个runloop中发布。

所以,如果你这样做:

@autoreleasepool {
  Stinker *aNewStink = [Stinker makeAStink];
  aNewStink = nil;
}

立即调用Dealloc方法。