天天看点

object-c 内存管理学习笔记

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

[pool drain]:这个函数可以把autoreleasePool里的对象释放

在for循环中每次都释放内存池的示例:

NSAutoreleasePool *tempPool;

…

for(i = 0; i<n;++i)

{

       tempPool= [[NSAutoReleasePool alloc] init];

       …//lots of work with temporary objects here

  [tempPool drain];

}
           

autoreleasePool保存了实际对象的引用,当调用drain函数的时候将其释放

将一个对象放入autoreleasePool中:[myFraction autorelease];

每次调用retain方法,对象的引用计数就会加1

[myFraction retain]

当一个对象被加入数组里,它的引用计数也会加1

当调用一次release函数后,该对象的引用计数会减1

[myFraction release]

当一个对象引用计数为0的时候,系统就会调用该对象的dealloc消息将其所占用的内存释放掉

当调用一个对象的retainCount消息时候,该消息会返回一个NSUInteger类型的正整数,这个数字代表当前该对象的引用计数。

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        // insert code here...
        NSNumber            *myInt = [[NSNumber alloc] initWithInteger:100];
        NSNumber            *myInt2;
        NSMutableArray      *myArr = [NSMutableArray array];
        
        NSLog(@"myInt retain count = %lx",(unsigned long)[myInt retainCount]);
        
        [myArr addObject:myInt];
        NSLog(@"after adding to array = %lx",(unsigned long)[myInt retainCount]);
        
        myInt2 = myInt;
        NSLog(@"after asssignment to myInt2 = %lx",(unsigned long)[myInt retainCount]);
        
        [myInt retain];
        NSLog(@"myInt after retain = %lx",(unsigned long)[myInt retainCount]);
        NSLog(@"myInt2 after retain = %lx",(unsigned long)[myInt2 retainCount]);
        
        [myInt release];
        NSLog(@"after release = %lx",(unsigned long)[myInt retainCount]);
        
        [myArr removeObjectAtIndex:0];
        NSLog(@"after removal from array = %lx",(unsigned long)[myInt retainCount]);
        
        [myInt2 release];
        [pool drain];
        
        return 0;
}
           

结果:

myInt retain count = 1

after adding to array = 2after asssignment to myInt2 = 2myInt after retain = 3

myInt2 after retain = 3

after release = 2

after removal from array = 1

myInt = [myArr ObejctAtIndex:0]
...
[myArr removeObjectAtIndex:0]
           

当数组移除对象后,myInt所指向的对象可能已经被回收,代码可能会崩溃

所以myInt在获得数组对象的时候,还需要调用一次retain

#import <UIKit/UIKit.h>

#import "AppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        
        NSString        *myStr1 = @"Constant string";
        NSString        *myStr2 = [NSString stringWithString:@"string 2"];
        NSMutableString *myStr3 = [NSMutableString stringWithString:@"string 3"];
        NSMutableArray  *myArr  = [NSMutableArray array];
        
        NSLog(@"Retain count:myStr1: %lx,myStr2:%lx,myStr3:%lx",(unsigned long)[myStr1 retainCount],(unsigned long)[myStr2 retainCount],(unsigned long)[myStr3 retainCount]);
        
        [myArr addObject:myStr1];
        [myArr addObject:myStr2];
        [myArr addObject:myStr3];
        
        NSLog(@"Retain count:myStr1: %lx,myStr2:%lx,myStr3:%lx",(unsigned long)[myStr1 retainCount],(unsigned long)[myStr2 retainCount],(unsigned long)[myStr3 retainCount]);
        
        [myStr1 retain];
        [myStr2 retain];
        [myStr3 retain];
        
        NSLog(@"Retain count:myStr1: %lx,myStr2:%lx,myStr3:%lx",(unsigned long)[myStr1 retainCount],(unsigned long)[myStr2 retainCount],(unsigned long)[myStr3 retainCount]);
        
        // Bring the reference count of myStr3 back down
        [myStr3 release];
        
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
           

结果:

Retain count: myStr1: fffffffffffffff, myStr2: fffffffffffffff, myStr3: 1Retain count: myStr1: fffffffffffffff, myStr2: fffffffffffffff, myStr3: 2Retain count: myStr1: fffffffffffffff, myStr2: fffffffffffffff, myStr3: 3

因为str1,str2是使用常量字符串初始化的,所以内存的分配和其他对象使用不一样的机制。常量字符串不会被release,所以它们使用引用计数机制,所以str1,str2打印的结构都是fffffffffff

当对一个对象调用retain消息的时候,在不用该对象的时候一定要记得调用其的release方法。通过copy,mutableCopy,alloc,new获得的对象也需要在使用结束后调用release方法

在ios程序中,一个事件循环会新建一个新的AutoreleasePool,并把之前的给drain掉,所以在这期间,任何没有retain的内存池对象都会被销毁。