iOS AutoReleasePool自动释放池

这是我查看了iOS源码之后,在结合这篇文章黑幕背后的Autorelease而总结出来的知识,在此向这位大神学习了。

AutoReleasePool自动释放池,一般理解就是自动帮OC对象添加release操作,一般涉及的问题有AutoRelease实现原理,什么时候释放,以及怎么释放的问题。
写个示例代码触发AutoReleasePool

@autoreleasepool{
NSString *strTest = [NSString stringWithFormat:@"test%i", 100]; // 这里必须要拼接字符串,不然系统会编译成常量字符串,那就不受AutoReleasePool操作了
  }

那么会编译成:

NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
NSString *strTest = [NSString stringWithFormat:@"test%i", 100]; // stringWithFormat里面也会调用autorelease,所以strTest这里不用调用autorelease
[pool drain];

这里要引入一个哨兵对象的概念,简单来说,就是一个对象存储着一个起始内存地址。

  • NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
    里面会调用NSAutoReleasePool 类的 push() 标记 一个哨兵对象 的内存地址,以NSAutoReleasePool成员变量的方式保存。
  • 在AutoReleasePool代码块里面 创建 的OC对象,都会标记到哨兵对象之后的内存块中。(其实就是类似Array添加对象,然后在释放后把Array里面的所有对象都给释放掉一样)
  • 调用 [pool drain] 的时候,实际是调用NSAutoReleasePool 的pop方法,然后把添加在哨兵对象之后的OC对象全部释放

AutoReleasePoolPage的源码大概是这样的流程

NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];       ------>  id context = AutoreleasePoolPage.push();
[obj1 autorelease]; -------> getHotPage().add(obj1); 添加到哨兵对象之后
[obj2 autorelease]; -------> getHotPage().add(obj2);
[pool drain]; -------> AutoreleasePoolPage.pop(context);

** 关于OC对象何时释放 **
然后在NSAutoRelasePool对象执行销毁时[pool drain]后,自动释放池会把添加到该pool里面的所有OC对象都执行一遍release(retainCount-=1),如果恰好此时retainCount<=0 ,那么系统会自动调用dealloc方法废弃对象。
如果你是在主线程里面写了一个用autoRelease 修饰的OC对象,但是没有给该对象指定自定义的NSAutoRelasePool,那么系统会把自动释放的OC对象添加到最近的NSAutoReleasePool中,即 main.m 里面的 autoreleasepool(注意主线程Runloop每次循环只是在这个autoreleasepool里面创建分页page,然后循环结束执行pop释放分页,并没有再新建autoreleasepool),这样的话只有等一次Runloop循环执行结束之后,该pool执行pop才会释放对象。
而 main 的 autoreleasepool,要等到APP结束运行的时候,才会彻底执行释放drain,即UIApplicationMain方法执行返回了。

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

目前在代码中创建局部对象,系统都会自动添加autoRelease修饰,那么主线程Runloop在每次循环结束时,会把本次Runloop循环里面所新建的OC对象都指定一次release,如果retainCount==0,那么该对象会被释放。
这样就存在一个情况:在一个函数A里面新建的局部对象Object1,在另一个函数B里面还是可以访问这个局部对象Object1,到函数C里面Object1被释放,就说明函数A和函数B的代码是在同一次Runloop里面执行的,而函数C是在下一次Runloop循环里面调用。

示例

最后附上查看线程池的方式:(NSAutoreleasePool 必须是MRC环境:设置MRC方式

// 因为showPools 未公开,只能这么调用了
IMP imp = [NSAutoreleasePool methodForSelector:@selector(showPools)]; 
if(imp != nil){
    ((void(*)(void))imp)();
}

// Developer Documentation里面搜索 NSAutoreleasePool 就可以找到方法说明
// Debugging
// [+showPools](apple-reference-documentation://hc4NqmvBGF)
// Displays the state of the current thread's autorelease pool stack to stderr
.

示例代码

//  main.m
int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[[NSObject alloc] init] autorelease];
        NSObject *obj1 = [[[NSObject alloc] init] autorelease];
        IMP imp = [NSAutoreleasePool methodForSelector:@selector(showPools)];
        if(imp != nil){
            ((void(*)(void))imp)();
        }
        
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

//  AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
    NSObject *objtemp =  [[[NSObject alloc] init] autorelease];;
    NSObject *objtemp1 = [[[NSObject alloc] init] autorelease];
    NSObject *objtemp2 =  [[[NSObject alloc] init] autorelease];
    
    IMP imp = [NSAutoreleasePool methodForSelector:@selector(showPools)];
    if(imp != nil){
        ((void(*)(void))imp)();
    }
    return YES;
}

输出结果:(上面几个autoRelease对象 都在同一个主线程释放池,但是在不同的区域(就是上面所说的分页))。

objc[7994]: ##############
objc[7994]: AUTORELEASE POOLS for thread 0x103de33c0
objc[7994]: 857 releases pending.
objc[7994]: [0x7faa43805000]  ................  PAGE (full)  (cold)
objc[7994]: [0x7faa43805038]  ################  POOL 0x7faa43805038
objc[7994]: [0x7faa43805040]    0x61800000a270  NSObject  --- 注意看这里 --- 
objc[7994]: [0x7faa43805048]    0x61800000a280  NSObject  --- 注意看这里 ---
objc[7994]: [0x7faa43805050]    0x618000036120  __NSCFString
objc[7994]: [0x7faa43805058]  ################  POOL 0x7faa43805058
......
**objc[7994]: [0x7faa43805098]  ################  POOL 0x7faa43805098**
objc[7994]: [0x7faa438050a0]    0x6080000b1d60  UIMutableApplicationSceneSettings
objc[7994]: [0x7faa438050a8]    0x60000006ea80  UIMutableApplicationSceneClientSettings
objc[7994]: [0x7faa438050b0]    0x600000034fa0  UIDevice
......
objc[7994]: [0x7faa42010b10]    0x61000006a580  __NSBundleTables
objc[7994]: [0x7faa42010b18]    0x610000084f10  NSBundle
objc[7994]: [0x7faa42010b20]    0x61800000a5f0  NSObject  --- 注意看这里 ---
objc[7994]: [0x7faa42010b28]    0x61800000a600  NSObject  --- 注意看这里 --- 
objc[7994]: [0x7faa42010b30]    0x61800000a610  NSObject  --- 注意看这里 --- 
objc[7994]: ##############
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容