內(nèi)存管理
ARC處理原理
ARC是Objective-C編譯器的特性,而不是運(yùn)行時(shí)特性或者垃圾回收機(jī)制躁倒,ARC所做的只不過(guò)是在代碼編譯時(shí)為你自動(dòng)在合適的位置插入release或autorelease琉雳,只要沒(méi)有強(qiáng)指針指向?qū)ο螅瑢?duì)象就會(huì)被釋放。
- 前端編譯器
前端編譯器會(huì)為“擁有的”每一個(gè)對(duì)象插入相應(yīng)的release語(yǔ)句税手。如果對(duì)象的所有權(quán)修飾符是__strong,那么它就是被擁有的需纳。如果在某個(gè)方法內(nèi)創(chuàng)建了一個(gè)對(duì)象芦倒,前端編譯器會(huì)在方法末尾自動(dòng)插入release語(yǔ)句以銷(xiāo)毀它。而類(lèi)擁有的對(duì)象(實(shí)例變量/屬性)會(huì)在dealloc方法內(nèi)被釋放不翩。事實(shí)上兵扬,你并不需要寫(xiě)dealloc方法或調(diào)用父類(lèi)的dealloc方法,ARC會(huì)自動(dòng)幫你完成一切口蝠。此外器钟,由編譯器生成的代碼甚至?xí)饶阕约簩?xiě)的release語(yǔ)句的性能還要好,因?yàn)榫庉嬈骺梢宰鞒鲆恍┘僭O(shè)妙蔗。在ARC中俱箱,沒(méi)有類(lèi)可以覆蓋release方法,也沒(méi)有調(diào)用它的必要灭必。ARC會(huì)通過(guò)直接使用objc_release來(lái)優(yōu)化調(diào)用過(guò)程狞谱。而對(duì)于retain也是同樣的方法乃摹。ARC會(huì)調(diào)用objc_retain來(lái)取代保留消息。
- ARC優(yōu)化器
雖然前端編譯器聽(tīng)起來(lái)很厲害的樣子跟衅,但代碼中有時(shí)仍會(huì)出現(xiàn)幾個(gè)對(duì)retain和release的重復(fù)調(diào)用孵睬。ARC優(yōu)化器負(fù)責(zé)移除多余的retain和release語(yǔ)句,確保生成的代碼運(yùn)行速度高于手動(dòng)引用計(jì)數(shù)的代碼伶跷。
下面關(guān)于Objective-C內(nèi)存管理的描述錯(cuò)誤的是
A 當(dāng)使用ARC來(lái)管理內(nèi)存時(shí)掰读,代碼中不可以出現(xiàn)autorelease
B autoreleasepool 在 drain 的時(shí)候會(huì)釋放在其中分配的對(duì)象
C 當(dāng)使用ARC來(lái)管理內(nèi)存時(shí),在線(xiàn)程中大量分配對(duì)象而不用autoreleasepool則可能會(huì)造成內(nèi)存泄露
D 在使用ARC的項(xiàng)目中不能使用NSZone
- 參考答案:A
- 理由:ARC只是在大多時(shí)候編譯自動(dòng)為我們添加上內(nèi)存管理的代碼叭莫,只是我們的源代碼看不到而已蹈集,但是在編譯時(shí),編譯器會(huì)添加上相關(guān)內(nèi)存管理代碼雇初。對(duì)于自動(dòng)釋放池拢肆,在drain時(shí)會(huì)將自動(dòng)釋放池中的所有對(duì)象的引用計(jì)數(shù)減一,若引用計(jì)數(shù)為0靖诗,則會(huì)自動(dòng)釋放掉其內(nèi)存郭怪。如果在線(xiàn)程中需要大量分配內(nèi)存,我們理應(yīng)添加上自動(dòng)釋放池刊橘,以防內(nèi)存泄露鄙才。比如在for循環(huán)中要分配大量的內(nèi)存處理數(shù)據(jù),那么我們應(yīng)該在for循環(huán)內(nèi)添加自動(dòng)釋放池促绵,在每個(gè)循環(huán)后就將內(nèi)存釋放掉攒庵,防止內(nèi)存泄露。在ARC項(xiàng)目中败晴,自然不能手動(dòng)使用NSZone浓冒,也不能調(diào)用父類(lèi)的dealloc。
MRC文件在ARC工程混合編譯時(shí)位衩,需要在文件的Compiler Flags上添加什么參數(shù)
A -shared
B -fno-objc-arc
C -fobjc-arc
D -dynamic
參考答案:B
什么情況使用 weak 關(guān)鍵字裆蒸,相比 assign 有什么不同?
- 什么情況使用weak關(guān)鍵字?
- 在 ARC 中,在有可能出現(xiàn)循環(huán)引用的時(shí)候,往往要通過(guò)讓其中一端使用 weak 來(lái)解決,比如: delegate 代理屬性
自身已經(jīng)對(duì)它進(jìn)行一次強(qiáng)引用,沒(méi)有必要再?gòu)?qiáng)引用一次,此時(shí)也會(huì)使用 weak,自定義 IBOutlet 控件屬性一般也使用 weak糖驴;當(dāng)然僚祷,也可以使用strong。 - weak與assign的不同?
- weak 此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系” (nonowning relationship)贮缕。為這種屬性設(shè)置新值時(shí)辙谜,設(shè)置方法既不保留新值,也不釋放舊值感昼。此特質(zhì)同assign類(lèi)似装哆, 然而在屬性所指的對(duì)象遭到摧毀時(shí),屬性值也會(huì)清空(nil out)。 而 assign 的“設(shè)置方法”只會(huì)執(zhí)行針對(duì)“純量類(lèi)型” (scalar type蜕琴,例如 CGFloat 或 NSlnteger 等)的簡(jiǎn)單賦值操作萍桌。
- assigin 可以用非 OC 對(duì)象,而 weak 必須用于 OC 對(duì)象
調(diào)用對(duì)象的release 方法會(huì)銷(xiāo)毀對(duì)象嗎?
不會(huì)凌简,調(diào)用對(duì)象的release 方法只是將對(duì)象的引用計(jì)數(shù)器-1上炎,當(dāng)對(duì)象的引用計(jì)數(shù)器為0的時(shí)候會(huì)調(diào)用了對(duì)象的dealloc 方法才能進(jìn)行釋放對(duì)象的內(nèi)存。
自動(dòng)釋放池常見(jiàn)面試代碼
for (int i = 0; i < someLargeNumber; ++i)
{
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@"%@",string);
}
問(wèn):以上代碼存在什么樣的問(wèn)題雏搂?如果循環(huán)的次數(shù)非常大時(shí)藕施,應(yīng)該如何修改?
存在問(wèn)題:?jiǎn)栴}處在每執(zhí)行一次循環(huán)凸郑,就會(huì)有一個(gè)string加到當(dāng)前runloop中的自動(dòng)釋放池中裳食,只有當(dāng)自動(dòng)釋放池被release的時(shí)候,自動(dòng)釋放池中的標(biāo)示了autorelease的這些數(shù)據(jù)所占用的內(nèi)存空間才能被釋放掉芙沥。假設(shè)诲祸,當(dāng)someLargeNumber大到一定程度時(shí),內(nèi)存空間將被耗盡而沒(méi)有被釋放掉憨愉,所以就出現(xiàn)了內(nèi)存溢出的現(xiàn)象烦绳。
解決辦法1:如果i比較大卿捎,可以用@autoreleasepool {}解決配紫,放在for循環(huán)外,循環(huán)結(jié)束后午阵,銷(xiāo)毀創(chuàng)建的對(duì)象躺孝,解決占據(jù)棧區(qū)內(nèi)存的問(wèn)題
解決方法2:如果i玩命大,一次循環(huán)都會(huì)造成自動(dòng)釋放池被填滿(mǎn)底桂,自動(dòng)釋放池放在for循環(huán)內(nèi)植袍,每次循環(huán)都將上一次創(chuàng)建的對(duì)象release
修改之后:
for(int i = 0; i<1000;i++){
NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc] init];
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@"%@",string);
//釋放池
[pool1 drain]; }
objective-C對(duì)象的內(nèi)存布局是怎樣的?
- 由于Objective-C中沒(méi)有多繼承籽懦,因此其內(nèi)存布局還是很簡(jiǎn)單的于个,就是:最前面有個(gè)isa指針,然后父類(lèi)的實(shí)例變量存放在子類(lèi)的成員變量之前
看下面的程序,第一個(gè)NSLog會(huì)輸出什么?這時(shí)str的retainCount是多少?第二個(gè)和第三個(gè)呢? 為什么?
NSMutableArray* ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"];
[str retain];
[aryaddObject:str];
NSLog(@”%@%d”,str,[str retainCount]);
[str retain];
[str release];
[str release];
NSLog(@”%@%d”,str,[str retainCount]);
[aryremoveAllObjects]
NSLog(@”%@%d”,str,[str retainCount]);
str的retainCount創(chuàng)建+1暮顺,retain+1厅篓,加入數(shù)組自動(dòng)+1 3
retain+1,release-1捶码,release-1 2
數(shù)組刪除所有對(duì)象羽氮,所有數(shù)組內(nèi)的對(duì)象自動(dòng)-1 1
回答person的retainCount值,并解釋為什么
Person * per = [[Person alloc] init]; 此時(shí)person 的retainCount的值是1 self.person = per;
在self.person 時(shí),如果是assign,person的 retainCount的值不變,仍為1 若是:retain person的retainCount的值加1,變?yōu)?
若是:copy person的retainCount值不變,仍為1
什么時(shí)候需要在程序中創(chuàng)建內(nèi)存池?
- 用戶(hù)自己創(chuàng)建的數(shù)據(jù)線(xiàn)程,則需要?jiǎng)?chuàng)建該線(xiàn)程的內(nèi)存池
如果我們不創(chuàng)建內(nèi)存池惫恼,是否有內(nèi)存池提供給我們?
- 界面線(xiàn)程維護(hù)著自己的內(nèi)存池档押,用戶(hù)自己創(chuàng)建的數(shù)據(jù)線(xiàn)程,則需要?jiǎng)?chuàng)建該線(xiàn)程的內(nèi)存池
蘋(píng)果是如何實(shí)現(xiàn)autoreleasepool的?
autoreleasepool以一個(gè)隊(duì)列數(shù)組的形式實(shí)現(xiàn),主要通過(guò)下列三個(gè)函數(shù)完成.
? objc_autoreleasepoolPush
? objc_autoreleasepoolPop
? objc_autorelease
看函數(shù)名就可以知道令宿,對(duì)autorelease分別執(zhí)行push叼耙、pop操作。銷(xiāo)毀對(duì)象時(shí)執(zhí)行release操作粒没。
objc使用什么機(jī)制管理對(duì)象內(nèi)存旬蟋?
- 通過(guò)引用計(jì)數(shù)器(retainCount)的機(jī)制來(lái)決定對(duì)象是否需要釋放。 每次runloop完成一個(gè)循環(huán)的時(shí)候革娄,都會(huì)檢查對(duì)象的 retainCount倾贰,如果retainCount為0,說(shuō)明該對(duì)象沒(méi)有地方需要繼續(xù)使用了拦惋,可以釋放掉了匆浙。
為什么要進(jìn)行內(nèi)存管理?
- 因?yàn)橐苿?dòng)設(shè)備的內(nèi)存極其有限,當(dāng)一個(gè)程序所占內(nèi)存達(dá)到一定值時(shí), 系統(tǒng)會(huì)發(fā)出內(nèi)存警告. 當(dāng)程序達(dá)到更大的值時(shí), 程序會(huì)閃退, 影響用戶(hù)體驗(yàn). 為了保證程序的運(yùn)行流暢, 必須進(jìn)行內(nèi)存管理
內(nèi)存管理的范圍?
- 管理所有繼承自NSObject的對(duì)象, 對(duì)基本數(shù)據(jù)類(lèi)型無(wú)效.是因?yàn)閷?duì)象和其他數(shù)據(jù)類(lèi)型在系統(tǒng)中存儲(chǔ)的空間不一樣,其他局部變量主要存儲(chǔ)在棧區(qū)(因?yàn)榛緮?shù)據(jù)類(lèi)型占用的存儲(chǔ)空間是固定的,一般存放于棧區(qū)),而對(duì)象存儲(chǔ)于堆中,當(dāng)代碼塊結(jié)束時(shí),這個(gè)代碼塊所涉及到的所有局部變量會(huì)自動(dòng)彈棧清空,指向?qū)ο蟮闹羔樢矔?huì)被回收,這時(shí)對(duì)象就沒(méi)有指針指向,但依然存在于堆內(nèi)存中,造成內(nèi)存泄露.
objc使用什么機(jī)制管理對(duì)象內(nèi)存(或者內(nèi)存管理方式有哪些)厕妖?(重點(diǎn))
- MRC(manual retain-release)手動(dòng)內(nèi)存管理
- ARC(automatic reference counting)自動(dòng)引用計(jì)數(shù)
- Garbage collection (垃圾回收)首尼。但是iOS不支持垃圾回收, ARC作為L(zhǎng)LVM3.0編譯器的一項(xiàng)特性, 在iOS5.0 (Xcode4) 版本后推出的。
- ARC的判斷準(zhǔn)則, 只要沒(méi)有強(qiáng)指針指向?qū)ο? 對(duì)象就會(huì)被釋放.
iOS是如何管理內(nèi)存的言秸?
這個(gè)問(wèn)題的話(huà)上一個(gè)問(wèn)題也提到過(guò),講下block的內(nèi)存管理,ARC下的黃金法則就行软能。
這里說(shuō)下swift里的內(nèi)存管理:
delgate照樣weak修飾,閉包前面用[weak self],swift里的新東西,unowned,舉例,如果self在閉包被調(diào)用的時(shí)候可能為空,則用weak,反之亦然,如果為空時(shí)使用了unowned,程序會(huì)崩潰,類(lèi)似訪(fǎng)問(wèn)了懸掛指針,在oc中類(lèi)似于unsafe_unretained,類(lèi)似assign修飾了oc對(duì)象,對(duì)象被銷(xiāo)毀后,被unowned修飾的對(duì)象不會(huì)為空,但是unowned訪(fǎng)問(wèn)速度更快,因?yàn)閣eak需要unwarp后才能使用
內(nèi)存管理的原則
- 只要還有人在使用這個(gè)對(duì)象, 那么這個(gè)對(duì)象就不會(huì)被回收
- 只有你想使用這個(gè)對(duì)象, 那么就應(yīng)該讓這個(gè)對(duì)象的引用計(jì)數(shù)器加1
- 當(dāng)你不想使用這個(gè)對(duì)象時(shí), 應(yīng)該讓對(duì)象的引用計(jì)數(shù)器減1
- 誰(shuí)創(chuàng)建, 就由誰(shuí)來(lái)release
- 如果你通過(guò)alloc, new, copy 來(lái)創(chuàng)建一個(gè)對(duì)象, 當(dāng)你不想用這個(gè)對(duì)象的時(shí)候就必須調(diào)用release 或者autorelease 讓引用計(jì)數(shù)器減1
- 不是你創(chuàng)建的就不用你負(fù)責(zé) release
- 誰(shuí)retain 誰(shuí)release
- 只要你調(diào)用了retain ,無(wú)論這個(gè)對(duì)象如何生成, 都需要調(diào)用release
- 總結(jié):
有加就應(yīng)該有減, 曾讓某個(gè)計(jì)數(shù)器加1, 就應(yīng)該讓其在最后減1
內(nèi)存管理研究的對(duì)象:
-
野指針:指針變量沒(méi)有進(jìn)行初始化或指向的空間已經(jīng)被釋放。
- 使用野指針調(diào)用對(duì)象方法举畸,會(huì)報(bào)異常查排,程序崩潰。
- 通常再調(diào)用完release方法后抄沮,把保存對(duì)象指針的地址清空跋核,賦值為nil,找oc中沒(méi)有空指針異常叛买,所以[nil retain]調(diào)用方法不會(huì)有異常砂代。
-
內(nèi)存泄露
- 如 Person * person = [Person new]; (對(duì)象提前賦值nil或者清空)在棧區(qū)的person已經(jīng)被釋放, 而堆區(qū)new產(chǎn)生的對(duì)象還沒(méi)有釋放, 就會(huì)造成內(nèi)存泄露
- 在MRC手動(dòng)引用計(jì)數(shù)器模式下, 造成內(nèi)存泄露的情況
- 沒(méi)有配對(duì)釋放,不符合內(nèi)存管理原則
- 對(duì)象提前賦值nil或者清空率挣,導(dǎo)致release不起作用刻伊。
僵尸對(duì)象 : 堆中已經(jīng)被釋放的對(duì)象(retainCount = 0)
空指針 : 指針賦值為空,nil
如何判斷對(duì)象已經(jīng)被銷(xiāo)毀
- 重寫(xiě)dealloc方法,對(duì)象銷(xiāo)毀時(shí)椒功,會(huì)調(diào)用捶箱,重寫(xiě)時(shí)一定要[super dealloc]
retainCount = 0,使用retain能否復(fù)活對(duì)象
- 已經(jīng)被釋放的對(duì)象無(wú)法復(fù)活
對(duì)象與對(duì)象之間存在的關(guān)系
- 繼承關(guān)系
- 組合關(guān)系(是一種強(qiáng)烈的包含關(guān)系)
- 依賴(lài)關(guān)系(對(duì)象作為方法參數(shù)傳遞)
對(duì)象的組合關(guān)系中蛾茉,確保成員變量不被提前釋放讼呢?
- 重寫(xiě)set方法,在set方法中谦炬,retain該對(duì)象悦屏。
成員變量的對(duì)象节沦,在哪里配對(duì)釋放?
- dealloc中釋放
對(duì)象組合關(guān)系中础爬,內(nèi)存泄露有哪幾種情況甫贯?
- set方法沒(méi)有retain對(duì)象
- 沒(méi)有release舊對(duì)象
- 沒(méi)有判斷向set方法中傳入的是否為同一個(gè)對(duì)象
正確重寫(xiě)set方法
- 判斷是否為同一對(duì)象
- release舊對(duì)象
- retain新對(duì)象
分別描述內(nèi)存管理要點(diǎn)、autorelease看蚜、release叫搁、NSAutoreleasePool?并說(shuō)明autorelease是什么時(shí)候被release的?簡(jiǎn)述什么時(shí)候由你負(fù)責(zé)釋放對(duì)象,什么時(shí)候不由你釋放?[NSAutoreleasePool release]和[NSAutoreleasePool drain]有什么區(qū)別?
內(nèi)存管理要點(diǎn):Objective-C 使用引用計(jì)數(shù)機(jī)制(retainCount)來(lái)管理內(nèi)存。
內(nèi)存每被引用一次,該內(nèi)存的引用計(jì)數(shù)+1,每被釋放一次引 用計(jì)數(shù)-1供炎。
當(dāng)引用計(jì)數(shù) = 0 的時(shí)候,調(diào)用該對(duì)象的 dealloc 方法,來(lái)徹底從內(nèi)存中刪除該對(duì)象渴逻。
alloc,allocWithZone,new(帶初始化)時(shí):該對(duì)象引用計(jì)數(shù) +1;
retain:手動(dòng)為該對(duì)象引用計(jì)數(shù) +1;
copy:對(duì)象引用計(jì)數(shù) +1;//注意copy的OC數(shù)據(jù)類(lèi)型是否有mutable,如有為深拷貝音诫,新對(duì)象計(jì)數(shù)為1惨奕,如果沒(méi)有,為淺拷貝竭钝,計(jì)數(shù)+1
mutableCopy:生成一個(gè)新對(duì)象,新對(duì)象引用計(jì)數(shù)為 1;
release:手動(dòng)為該對(duì)象引用計(jì)數(shù) -1;
autorelease:把該對(duì)象放入自動(dòng)釋放池,當(dāng)自動(dòng)釋放池釋放時(shí),其內(nèi)的對(duì)象引用計(jì)數(shù) -1梨撞。
NSAutoreleasePool: NSAutoreleasePool是通過(guò)接收對(duì)象向它發(fā)送的autorelease消息,記錄該對(duì)象的release消息,當(dāng)自動(dòng)釋放池被銷(xiāo)毀時(shí),會(huì)自動(dòng)向池中的對(duì)象發(fā)送release消息。
autorelease 是在自動(dòng)釋放池被銷(xiāo)毀,向池中的對(duì)象發(fā)送release
只能釋放自己擁有的對(duì)象香罐。區(qū)別是:在引用計(jì)數(shù)環(huán)境下(在不使用ARC情況下),兩者基本一樣,在GC(垃圾回收制)環(huán)境下,release 是一個(gè)no-op(無(wú)效操作),所以無(wú)論是不是GC都使用drain
面試中內(nèi)存管理,release和autorelease的含義?這里尤其要強(qiáng)調(diào)下autorelease,它引申出自動(dòng)釋放池,也能引申出Run loop!
自動(dòng)釋放池是什么,如何工作 ?
- 什么是自動(dòng)釋放池:用來(lái)存儲(chǔ)多個(gè)對(duì)象類(lèi)型的指針變量
- 自動(dòng)釋放池對(duì)池內(nèi)對(duì)象的作用:存入池內(nèi)的對(duì)象卧波,當(dāng)自動(dòng)釋放池被銷(xiāo)毀時(shí),會(huì)對(duì)池內(nèi)對(duì)象全部做一次release操作
- 對(duì)象如何加入池中:調(diào)用對(duì)象的autorelease方法
- 自動(dòng)釋放池能嵌套使用嗎:能
- 自動(dòng)釋放池何時(shí)被銷(xiāo)毀 :簡(jiǎn)單的看庇茫,autorelease的"}"執(zhí)行完以后港粱。而實(shí)際情況是Autorelease對(duì)象是在當(dāng)前的runloop迭代結(jié)束時(shí)釋放的,而它能夠釋放的原因是系統(tǒng)在每個(gè)runloop迭代中都加入了自動(dòng)釋放池Push和Pop
- 多次調(diào)用對(duì)象的autorelease方法會(huì)導(dǎo)致:野指針異常
- 自動(dòng)釋放池的作用:將對(duì)象與自動(dòng)釋放池建立關(guān)系港令,池子內(nèi)調(diào)用autorelease啥容,在自動(dòng)釋放池銷(xiāo)毀時(shí)銷(xiāo)毀對(duì)象锈颗,延遲release銷(xiāo)毀時(shí)間
自動(dòng)釋放池什么時(shí)候釋放顷霹?
- 通過(guò)Observer監(jiān)聽(tīng)RunLoop的狀態(tài),一旦監(jiān)聽(tīng)到RunLoop即將進(jìn)入睡眠等待狀態(tài)击吱,就釋放自動(dòng)釋放池(kCFRunLoopBeforeWaiting)
IPhone OS有沒(méi)有垃圾回收?autorelease 和垃圾回收制(gc)有什么關(guān)系?
- iOS 中沒(méi)有垃圾回收淋淀。autorelease只是延遲釋放,gc是每隔一段時(shí)間詢(xún)問(wèn)程序,看是否有無(wú)指針指向的對(duì)象,若有,就將它回收。他們兩者沒(méi)有什么關(guān)系覆醇。
ARC問(wèn)題
- 什么是arc機(jī)制:自動(dòng)引用計(jì)數(shù).
- 系統(tǒng)判斷對(duì)象是否銷(xiāo)毀的依據(jù):指向?qū)ο蟮膹?qiáng)指針是否被銷(xiāo)毀
- arc的本質(zhì):對(duì)retainCount計(jì)算朵纷,創(chuàng)建+1 清空指針 - 1 或者到達(dá)autoreleasepool的大括號(hào)-1
- arc目的:不需要程序員關(guān)心retain和release操作.
- 如何解決arc機(jī)制下類(lèi)的相互引用:.h文件中使用@class關(guān)鍵字聲明一個(gè)類(lèi),兩端不能都用強(qiáng)指針永脓,一端用strong一端用weak
ARC通過(guò)什么方式幫助開(kāi)發(fā)者管理內(nèi)存袍辞?
ARC相對(duì)于MRC,不是在編譯時(shí)添加retain/release/autorelease這么簡(jiǎn)單常摧。應(yīng)該是編譯期和運(yùn)行期兩部分共同幫助開(kāi)發(fā)者管理內(nèi)存搅吁。
- 在編譯期威创,ARC用的是更底層的C接口實(shí)現(xiàn)的retain/release/autorelease,這樣做性能更好谎懦,也是為什么不能在ARC環(huán)境下手動(dòng)retain/release/autorelease肚豺,同時(shí)對(duì)同一上下文的同一對(duì)象的成對(duì)retain/release操作進(jìn)行優(yōu)化(即忽略掉不必要的操作)
- ARC也包含運(yùn)行期組件,這個(gè)地方做的優(yōu)化比較復(fù)雜界拦,但也不能被忽略吸申,手動(dòng)去做未必優(yōu)化得好,因此直接交給編譯器來(lái)優(yōu)化享甸,相信蘋(píng)果吧截碴!
開(kāi)發(fā)項(xiàng)目時(shí)你是怎么檢查內(nèi)存泄露
- 靜態(tài)分析 analyze
- instruments工具里面有個(gè)leak 可以動(dòng)態(tài)分析
如果在block中多次使用 weakSelf的話(huà),可以在block中先使用strongSelf蛉威,防止block執(zhí)行時(shí)weakSelf被意外釋放
對(duì)于非ARC隐岛,將 __weak 改用為 __block 即可
麻煩你設(shè)計(jì)個(gè)簡(jiǎn)單的圖片內(nèi)存緩存器(移除策略是一定要說(shuō)的)
- 內(nèi)存緩存是個(gè)通用話(huà)題,每個(gè)平臺(tái)都會(huì)涉及到瓷翻。cache算法會(huì)影響到整個(gè)app的表現(xiàn)聚凹。候選人最好能談下自己都了解哪些cache策略及各自的特點(diǎn)。
- 常見(jiàn)的有FIFO,LRU,LFU等等齐帚。由于NSCache的緩存策略不透明妒牙,一些app開(kāi)發(fā)者會(huì)選擇自己做一套cache機(jī)制,其實(shí)并不難对妄。
- FIFO : 新訪(fǎng)問(wèn)的數(shù)據(jù)插入FIFO隊(duì)列尾部湘今,數(shù)據(jù)在FIFO隊(duì)列中順序移動(dòng);淘汰FIFO隊(duì)列頭部的數(shù)據(jù)剪菱;
- LRU : 新數(shù)據(jù)插入到鏈表頭部摩瞎;每當(dāng)緩存數(shù)據(jù)命中,則將數(shù)據(jù)移到鏈表頭部孝常;當(dāng)鏈表滿(mǎn)的時(shí)候旗们,將鏈表尾部的數(shù)據(jù)丟棄;
- LFU : 新加入數(shù)據(jù)插入到隊(duì)列尾部(因?yàn)橐糜?jì)數(shù)為1)构灸;隊(duì)列中的數(shù)據(jù)被訪(fǎng)問(wèn)后上渴,引用計(jì)數(shù)增加,隊(duì)列重新排序喜颁;當(dāng)需要淘汰數(shù)據(jù)時(shí)稠氮,將已經(jīng)排序的列表最后的數(shù)據(jù)塊刪除;
常見(jiàn)的出現(xiàn)內(nèi)存循環(huán)引用的場(chǎng)景有哪些半开?
- 定時(shí)器(NSTimer):NSTimer經(jīng)常會(huì)被作為某個(gè)類(lèi)的成員變量隔披,而NSTimer初始化時(shí)要指定self為target,容易造成循環(huán)引用(self->timer->self)寂拆。 另外奢米,若timer一直處于validate的狀態(tài)芥炭,則其引用計(jì)數(shù)將始終大于0,因此在不再使用定時(shí)器以后恃慧,應(yīng)該先調(diào)用invalidate方法
- block的使用:block在copy時(shí)都會(huì)對(duì)block內(nèi)部用到的對(duì)象進(jìn)行強(qiáng)引用(ARC)或者retainCount增1(非ARC)园蝠。在ARC與非ARC環(huán)境下對(duì)block使用不當(dāng)都會(huì)引起循環(huán)引用問(wèn)題, 一般表現(xiàn)為痢士,某個(gè)類(lèi)將block作為自己的屬性變量彪薛,然后該類(lèi)在block的方法體里面又使用了該類(lèi)本身,簡(jiǎn)單說(shuō)就是self.someBlock =Type var{[self dosomething];或者self.otherVar = XXX;或者_(dá)otherVar = …};出現(xiàn)循環(huán)的原因是:self->block->self或者self->block->_ivar(成員變量)
- 代理(delegate):在委托問(wèn)題上出現(xiàn)循環(huán)引用問(wèn)題已經(jīng)是老生常談了怠蹂,規(guī)避該問(wèn)題的殺手锏也是簡(jiǎn)單到哭善延,一字訣:聲明delegate時(shí)請(qǐng)用assign(MRC)或者weak(ARC),千萬(wàn)別手賤玩一下retain或者strong城侧,畢竟這基本逃不掉循環(huán)引用了易遣!
對(duì)象添加到通知中心中,當(dāng)通知中心發(fā)通知時(shí)嫌佑,這個(gè)對(duì)象卻已經(jīng)被釋放了豆茫,可能會(huì)出現(xiàn)什么問(wèn)題?
- 其實(shí)這種只是考查對(duì)通知的簡(jiǎn)單應(yīng)用屋摇。通知是多對(duì)多的關(guān)系揩魂,主要使用場(chǎng)景是跨模塊傳值。當(dāng)某對(duì)象加入到通知中心后炮温,若在對(duì)象被銷(xiāo)毀前不將該對(duì)象從通知中心中移除火脉,當(dāng)發(fā)送通知時(shí),就會(huì)造成崩潰柒啤。這是很常見(jiàn)的倦挂。所以,在添加到通知中心后担巩,一定要在釋放前移除方援。
ARC下不顯式指定任何屬性關(guān)鍵字時(shí),默認(rèn)的關(guān)鍵字都有哪些兵睛?
- 對(duì)于基本數(shù)據(jù)類(lèi)型默認(rèn)關(guān)鍵字是:atomic,readwrite,assign
- 對(duì)于普通的Objective-C對(duì)象:atomic,readwrite,strong
寫(xiě)一個(gè)便利構(gòu)造器
+(id)Person {
Person *person=[Person alloc]init];
return [person autorelease]; 備注:ARC時(shí)不用 autorelease
}
寫(xiě)出下面程序段的輸出結(jié)果
NSDictionary *dict = [NSDictionary dictionaryWithObject:@"a string value" forKey:@"akey"]; NSLog(@"%@", [dict objectForKey:@"akey"]);
[dict release];
打印輸出 a string value,然后崩潰----原因:便利構(gòu)造器創(chuàng)建的對(duì)象,之后的release,會(huì)造成過(guò)度釋放
請(qǐng)寫(xiě)出以下代碼的執(zhí)行結(jié)果
NSString * name = [ [ NSString alloc] init ];
name = @”Habb”;
[ name release];
打印輸出結(jié)果是: Habb,在[name release]前后打印均有輸出結(jié)果 ---會(huì)造成內(nèi)存泄露---原先指向的區(qū)域變成了野指針,之后的釋放,不能釋放之前創(chuàng)建的區(qū)域
寫(xiě)出方法獲取ios內(nèi)存使用情況肯骇?
iOS是如何管理內(nèi)存的?
我相信很多人的回答是內(nèi)存管理的黃金法則祖很,其實(shí)如果我是面試官,我想要的答案不是這樣的漾脂。我希望的回答是工作中如何處理內(nèi)存管理的假颇。
參考答案:
- Block內(nèi)存管理:由于使用block很容易造成循環(huán)引用,因此一定要小心內(nèi)存管理問(wèn)題骨稿。最好在基類(lèi)controller下重寫(xiě)dealloc笨鸡,加一句打印日志姜钳,表示類(lèi)可以得到釋放。如果出現(xiàn)無(wú)打印信息形耗,說(shuō)明這個(gè)類(lèi)一直得不到釋放哥桥,表明很有可能是使用block的地方出現(xiàn)循環(huán)引用了。對(duì)于block中需要引用外部controller的屬性或者成員變量時(shí)激涤,一定要使用弱引用拟糕,特別是成員變量像_testId這樣的,很多人都沒(méi)有使用弱引用倦踢,導(dǎo)致內(nèi)存得不到釋放送滞。
- 對(duì)于普通所創(chuàng)建的對(duì)象,因?yàn)楝F(xiàn)在都是ARC項(xiàng)目辱挥,所以記住內(nèi)存管理的黃金法則就可以解決犁嗅。
很多內(nèi)置的類(lèi),如tableview的delegate的屬性是assign不是retain晤碘?
- tableview的代理一般都是它所屬的控制器褂微,控制器會(huì)對(duì)它內(nèi)部的view進(jìn)行一次retain操作,而tableview對(duì)代理控制器也進(jìn)行一次retain操作园爷,就會(huì)出現(xiàn)循環(huán)引用問(wèn)題蕊梧。
文章如有問(wèn)題,請(qǐng)留言腮介,我將及時(shí)更正肥矢。
滿(mǎn)地打滾賣(mài)萌求贊,如果本文幫助到你叠洗,輕點(diǎn)下方的紅心甘改,給作者君增加更新的動(dòng)力。