autoreleasepool释放时机

最开始只是想试一试写在方法内部的局部变量释放时经不经过autoreleasepool。

例如,下图这样的代码。

xxx.png

为了不影响对象本身的引用计数影响它的销毁过程,使用一个weak指针,不出所料的,打印出来了如下结果

001.png

但是这个实验如果换成NSString得到的则是完全不一样的结果。

如下代码

002.png

打印出来的结果却是:

003.png

这个看上去也很好似乎也很好理解,NSString初始化的时候是存放在常量区的,所以没有释放嘛。

深入研究

为了观察对象的释放过程,我们在str赋值的地方加一个断点

breakpoint.png

走到该断点的时候通过lldb命令watchpoint set variable str来观察,可以看到str由0x0000000000000000变成0x00000001056b3250。

04.png

然后一路点击Continue program execution,发现str会变成0x0000000000000000,控制台只打印了一次str的值,也就是说viewwillappear还没有执行,这点跟雷大博客(Objective-C Autorelease Pool 的实现原理)中的略不一样,我猜是apple改了。

05.png

然后看左侧的方法调用栈,会发现这个过程经过了objc_store,AutoreleasePoolPage::pop(void *)等函数通过autoreleasepool释放了。现在修改一下log语句。

06.png

看了几个大神之前的博客,大都还打印了retainCount,但是今天这里研究的是arc,就不打印retainCount了。

执行如下代码:

074.png

得到打印结果:

066.png

可以看到这里其实是有三种String的,而references指向了cstr,此时在viewWillAppear和viewDidAppear里打印references得到的则是null。

三种String

  • NSCFConstantString: 字符串常量,放在常量区,对其retain或者release不影响它的引用计数,程序结束后释放。用字面量语法创建出来的string就是这种,所以在出了viewDidLoad方法以后在其他地方也能打印出值,压根就没释放。
077.png
  • NSTaggedPointerString: Tagged Point,标签指针,苹果在64位环境下对NSString和NSNumber做的一些优化,简单来说就是把对象的内容存放在了指针里,这样就不需要在堆内存里在开辟一块空间存放对象了,一般用来优化长度较小的内容。关于标签指针的内容可以参考唐巧的介绍:深入理解Tagged Pointer

对于NSString,当非字面量的数字,英文字母字符串的长度小于等于9的时候会自动成为NSTaggedPointerString类型。代码中的bstr如果再加一位或者有中文在里面就是变成NSCFString。而NSTaggedPointerString也是不会释放的,它的内容就在本身的指针里,又没有对象释放个啥啊。所以如果把references的赋值代码改为

08.png

在viewWillAppear和viewDidAppear中也是能打印出值来的。

NSCFString: 这种string就和普通的对象很像了,储存在堆上,有正常的引用计数,需要程序员分配释放。所以references = cstr时,会打印出null,cstr出了方法作用域在runloop结束时就被autoreleasepool释放了。

stringWithFormat

到这里还是有问题

09.png

根据以上说法,当string超过10位数时,bstr和cstr都是NSCFString,可是两种情况viewWillAppear和viewDidAppear在打印的结果不一样。

bstr:

10.png

cstr:

11.png

根据太阳神黑幕背后的Autorelease中的说法,是因为viewWillAppear和viewDidLoad在一个runloop中导致bstr在willappear中能打印出来值。如果真的是这样那cstr讲道理应该也能打印出值来,文章最开始用NSObject做实验时在viewWillAppear时应该也能打印出值来。

所以其实并不是同一个runloop的问题,问题出在stringWithFormat这个工厂方法上。

查资料得知以 alloc, copy, init,mutableCopy和new这些方法打头的方法,返回的都是 retained return value,例如[[NSString alloc] initWithFormat:],而其他的则是unretained return value,例如 [NSString stringWithFormat:]。对于前者调用者是要负责释放的,对于后者就不需要了。而且对于后者ARC会把对象的生命周期延长,确保调用者能拿到并且使用这个返回值,但是并不一定会使用 autorelease,在worst case 的情况下才可能会使用,因此调用者不能假设返回值真的就在 autorelease pool中。从性能的角度,这种做法也是可以理解的。如果我们能够知道一个对象的生命周期最长应该有多长,也就没有必要使用 autorelease 了,直接使用 release 就可以。如果很多对象都使用 autorelease 的话,也会导致整个 pool 在 drain 的时候性能下降。

也就是说通过工厂方法得到的string生命周期被延长了,所以才会在viewWillAppear里依然可以打印出来。为了证实这一点,我们换成array来做个实验。

14.png

第一种情况通过字面量创建array,打印台输出:

15.png

第二种情况通过工厂方法创建,打印台输出:

16.png

可以看到通过工厂方法创建的array生命周期确实被延长了。

总结

1.方法里的临时变量是会通过autoreleasepool释放的

2.NSCFString跟普通对象一样是可以释放的

3.NSString和NSArray的工厂方法可以延长对象的生命周期(同理,NSDictionary也是一样的,有兴趣的可以试一下)

——————————————转载自http://www.cocoachina.com/ios/20170303/18829.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容

  • 1、[NSObject alloc]在创建完对象后,会让该对象的retainCount+1,后续的init为初始化...
    naiyi阅读 1,507评论 0 4
  • 目录 autorelease的本质 autorelease对象什么时候释放? autoreleasepool的工作...
    yanhooIT阅读 5,132评论 5 35
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,068评论 1 32
  • 局部释放池 创建一个新的自动释放池的方法:ARC下: 这相当于MRC下: 其中对象s会被加入到自动释放池,当ARC...
    thinkq阅读 16,649评论 8 40
  • 内存的引用   计算机是按地址访问数据,如果一块内存被使用,就必须让外界知道它在哪儿,反过来讲,要访问一个数据就必...
    吸血鬼de晚餐阅读 2,006评论 0 5