国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

RunLoop和autorelease的一道面試題

2019-11-14 19:12:22
字體:
供稿:網(wǎng)友

有這么一道ios面試題 以下代碼有沒有什么問題?如果有?如何解決?

for (int i = 0 ; i < largeNumber; i++) {		NSString *str = [NSString stringWithFormat:@"hello -%04d",i];	str = [str stringByAppendingString:@" - world"]; }

局部釋放池和RunLoop釋放池的概念:

主線程的RunLoop是默認(rèn)開啟的(視圖用[[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]]來停止它,也是做不到的), 每一次消息循環(huán)開始的時候會先創(chuàng)建自動釋放池,這次循環(huán)結(jié)束前,會釋放自動釋放池,然后RunLoop等待下次事件源。 在這個過程中,由RunLoop創(chuàng)建的釋放池類似于一個全局的釋放池。但是開發(fā)者可以任何執(zhí)行的地方創(chuàng)建釋放池,也就是局部的釋放池,這時的釋放池類似于代碼塊 當(dāng)釋放池結(jié)束的時候會自動釋放。因此一般情況下,局部的自動釋放池很快就被釋放了,而RunLoop釋放池會等一次消息循環(huán)結(jié)束的時候釋放。

什么樣的對象會交給釋放池管理:

返回當(dāng)前類的實例的類方法創(chuàng)建出來的對象,都是autorelease的,會交給所在的釋放池進(jìn)行管理。 例如創(chuàng)建一個Person類,使用[[self alloc]init]方法創(chuàng)建的對象的管理不會交給它所在的釋放池,而是根據(jù)引用計數(shù)來控制釋放的時機(jī), 如果使用[[[self alloc]init] autorelease]創(chuàng)建的對象,會交給所在的釋放池管理,控制其釋放的時機(jī)。

- (void)test{	@autoreleasepool {        Person *p = [[Person alloc]init];        p = nil;        NSLog(@"---");    }    NSLog(@"autorelease結(jié)束");}

執(zhí)行結(jié)果:

Person---dealloc---autorelease結(jié)束

 

- (void)test1{        @autoreleasepool {        Person *p = [Person person]; // 內(nèi)部是[[[self alloc]init] autorelease]        p = nil;        NSLog(@"---");    }    NSLog(@"autorelease結(jié)束");}

執(zhí)行的結(jié)果為:

---Person---deallocautorelease結(jié)束

因此自動釋放池被銷毀或耗盡時會向池中所有使用autorelease創(chuàng)建的對象發(fā)送release 消息,釋放所有autorelease的對象,而不是所有的對象。

回到面試的問題:

當(dāng)我們使用for循環(huán)創(chuàng)建很多個使用autorelease方式創(chuàng)建的NSString對象的時候,將所有的對象的釋放權(quán)都交給了RunLoop 的釋放池,而RunLoop的釋放池會等待這個事件處理之后才會釋放,因此就會使對象無法及時釋放,堆積在內(nèi)存造成內(nèi)存泄露,可以在Debug Navigation 中觀察到內(nèi)存激增。為了驗證確實是因為autorelease這種創(chuàng)建方式引起的內(nèi)存泄露,我做了如下的測試:

int largeNumber = 100000000;- (void)test3{    for (int i = 0 ; i < largeNumber; i++) {        NSString *str = [[NSString alloc]initWithFormat:@"hello -%04d",i];        str = [str stringByAppendingString:@" - world"];    }}// 將stringWithFormat:方法換成了alloc+initWithFormat:// 這樣做的結(jié)果是內(nèi)存幾乎沒有變化,驗證了內(nèi)存飆升確實是autorelease創(chuàng)建方式造成的。

但是在編寫代碼的時候我們?nèi)匀涣?xí)慣用類的快速創(chuàng)建方法,而不是alloc+init。也就是說,為了方便寫程序,又使用了底層實現(xiàn)是alloc+init+autorelease的快速創(chuàng)建對象的方法(如 stringWithFormat:)。因此解決的方案就是添加局部的釋放池,以及時釋放內(nèi)存,如果將局部釋放池添加到循環(huán)外:

- (void)test4{    @autoreleasepool {        for (int i = 0 ; i < largeNumber; i++) {            NSString *str = [NSString stringWithFormat:@"hello -%04d",i];            str = [str stringByAppendingString:@" - world"];        }    }}

這樣顯然是沒有效果的,釋放池需要等循環(huán)執(zhí)行之后再釋放內(nèi)存,這和使用RunLoop創(chuàng)建的釋放池沒有什么區(qū)別。 較好的方案就是每次循環(huán)的時候添加一個釋放池:

- (void)test5{    for (int i = 0 ; i < largeNumber; i++) {        @autoreleasepool {            NSString *str = [NSString stringWithFormat:@"hello -%04d",i];            str = [str stringByAppendingString:@" - world"];        }    }}

這樣每一次循環(huán)的結(jié)束時都會釋放一次內(nèi)存,因而這個循環(huán)全部執(zhí)行完成時也幾乎補(bǔ)不消耗內(nèi)存。

總結(jié)是:

做多線程開發(fā)時,需要在線程調(diào)度方法中手動添加自動釋放池,尤其是當(dāng)執(zhí)行循環(huán)的時候,如果循環(huán)內(nèi)部有使用類的快速創(chuàng)建方法創(chuàng)建的對象, 一定要將循環(huán)體放到自動釋放池中。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 怀安县| 南澳县| 招远市| 海林市| 东乡族自治县| 唐海县| 镇坪县| 贵州省| 泌阳县| 济宁市| 禹城市| 潼关县| 大城县| 江油市| 紫云| 洪洞县| 阳信县| 石阡县| 枣庄市| 宜城市| 教育| 东宁县| 波密县| 梁平县| 绥棱县| 南京市| 毕节市| 通辽市| 荔浦县| 藁城市| 淮阳县| 房产| 洮南市| 黄浦区| 双鸭山市| 五家渠市| 绥阳县| 石渠县| 深州市| 根河市| 无棣县|