一道偷、關(guān)于內(nèi)存管理
應(yīng)用程序內(nèi)存管理是在程序運(yùn)行時(shí)分配、使用以及在使用完成后釋放的過(guò)程臭胜。一個(gè)寫得好的程序使用盡可能少的內(nèi)存逐哈。
雖然內(nèi)存管理通常是在單個(gè)對(duì)象的級(jí)別上考慮的饰躲,但您的目標(biāo)實(shí)際上是管理對(duì)象圖薛闪。
兩種內(nèi)存管理的方式:
MRC:可以通過(guò)跟蹤自己擁有的對(duì)象來(lái)顯式管理內(nèi)存唇牧。使用引用計(jì)數(shù)的模型來(lái)實(shí)現(xiàn)风范。
ARC:系統(tǒng)使用與MRC相同的引用計(jì)數(shù)系統(tǒng)肾档,但它在編譯時(shí)插入了適當(dāng)?shù)膬?nèi)存管理方法摹恰。(建議使用)
兩個(gè)內(nèi)存方面的常見(jiàn)問(wèn)題:
釋放或覆蓋仍在使用的數(shù)據(jù)
這會(huì)導(dǎo)致內(nèi)存損壞,通常會(huì)導(dǎo)致應(yīng)用程序崩潰怒见,或者更糟糕的是用戶數(shù)據(jù)損壞俗慈。
不釋放不再使用的數(shù)據(jù)會(huì)導(dǎo)致內(nèi)存泄漏
內(nèi)存泄漏是分配的內(nèi)存不被釋放的地方,即使它再也不會(huì)被使用遣耍。泄漏導(dǎo)致您的應(yīng)用程序使用越來(lái)越多的內(nèi)存闺阱,這反過(guò)來(lái)可能導(dǎo)致系統(tǒng)性能低下或您的應(yīng)用程序被終止。
二舵变、內(nèi)存管理的基本規(guī)則
1酣溃、你擁有你創(chuàng)建的對(duì)象:
使用一個(gè)以“alloc”、“new”纪隙、“copy”或“mutableCopy”(例如赊豌,alloc、newObject或mutableCopy)開(kāi)頭的方法創(chuàng)建一個(gè)對(duì)象绵咱。
2碘饼、您可以使用retain(strong)獲取對(duì)象的所有權(quán):
通常保證接收到的對(duì)象在接收到的方法中保持有效,并且該方法還可以安全地將對(duì)象返回到其調(diào)用者悲伶。
3艾恼、當(dāng)你不再需要它時(shí),你必須放棄所有權(quán):
通過(guò)發(fā)送release消息或autorelease消息來(lái)放棄對(duì)對(duì)象的所有權(quán)麸锉。
4钠绍、你不能放棄對(duì)你不擁有的物品的所有權(quán)
注意:
1、使用autoRelease延遲釋放
2花沉、你不擁有被引用返回的對(duì)象
3五慈、當(dāng)應(yīng)用程序終止時(shí),對(duì)象可能不會(huì)被發(fā)送dealloc消息主穗。
由于進(jìn)程的內(nèi)存在退出時(shí)會(huì)自動(dòng)清除,所以簡(jiǎn)單地允許操作系統(tǒng)清理資源比調(diào)用所有內(nèi)存管理方法更有效毙芜。
4忽媒、CoreFoundation使用類似當(dāng)不相同的規(guī)則
三、實(shí)用的內(nèi)存管理
1腋粥、使用訪問(wèn)器方法使內(nèi)存管理更容易:
使用方法構(gòu)造器對(duì)實(shí)例變量賦值晦雨;
不要再init和dealloc方法使用方法構(gòu)造器
2架曹、使用weak避免引用循環(huán)
3、避免使用中的對(duì)象被釋放
4闹瞧、不要使用dealloc來(lái)管理稀缺資源
如果不這樣的話绑雄,會(huì)導(dǎo)致以下問(wèn)題
1、tear-down機(jī)制本質(zhì)上是無(wú)序的奥邮,如果對(duì)象被意外釋放執(zhí)行dealloc
例如万牺,tear-down順序可能會(huì)改變,這可能會(huì)導(dǎo)致意外的結(jié)果洽腺。
2脚粟、稀缺資源沒(méi)有被釋放
內(nèi)存泄漏是應(yīng)該修復(fù)的錯(cuò)誤,但它們通常不會(huì)立即致命蘸朋。
然而核无,如果當(dāng)你期望稀缺資源被釋放時(shí),稀缺資源沒(méi)有被釋放藕坯,你可能會(huì)遇到更嚴(yán)重的問(wèn)題团南。
例如,如果應(yīng)用程序耗盡了文件描述符炼彪,用戶可能無(wú)法保存數(shù)據(jù)吐根。
3、清理邏輯在錯(cuò)誤的線程上執(zhí)行霹购。
如果一個(gè)對(duì)象是在一個(gè)意外的時(shí)間自動(dòng)釋放的佑惠,它將被分配在任何線程的自動(dòng)釋放池塊上。
如果它恰好是在對(duì)于只應(yīng)從一個(gè)線程中觸及的資源來(lái)說(shuō)齐疙,這很容易是致命的膜楷。
5、集合擁有它們所包含的對(duì)象(array,dic,set)
添加到集合中時(shí)贞奋,對(duì)象的引用計(jì)數(shù)+1赌厅。
從集合中移除,或者集合本身被釋放時(shí)轿塔,對(duì)象的引用計(jì)數(shù)-1特愿。
四、使用AutoreleasePool
1勾缭、關(guān)于autoreleasePool
autoreleasePool提供了一種機(jī)制揍障,你可以丟掉對(duì)一個(gè)對(duì)象的所有權(quán),但是不會(huì)導(dǎo)致對(duì)象立即被釋放掉俩由。
使用方式:
@autoreleasepool {
// Code that creates autoreleased objects.
}
在autoreleasepool結(jié)束的時(shí)候毒嫡,在block塊里面被標(biāo)記為autorelease的對(duì)象會(huì)收到一次release消息。
autoreleasepool可以嵌套使用幻梯。
AppKit和UIKit在每次runloop時(shí)兜畸,都會(huì)放到autoreleasepool的block中使用努释。所以一般來(lái)說(shuō)不用顯性的手動(dòng)創(chuàng)建。
除非以下幾種情況:
1咬摇、如果你沒(méi)有基于UI framework寫程序伐蒂,如一個(gè)command-line工具
2、你寫了一個(gè)循環(huán)逸邦,創(chuàng)建了很多的臨時(shí)對(duì)象
此時(shí)你需要?jiǎng)?chuàng)建一個(gè)autoreleasePool,在每次循環(huán)結(jié)束的時(shí)候釋放掉臨時(shí)變量
3龄坪、你創(chuàng)建了一個(gè)輔助線程(貌似只有舊版本會(huì)有問(wèn)題)
2、使用本地自動(dòng)釋放池塊減少峰值內(nèi)存足跡
例子:
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
@autoreleasepool {
NSError *error;
NSString *fileContents = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding error:&error];
/* Process the string, creating and autoreleasing more objects. */
}
}
三健田、Autorelease Pool Block和線程
Cocoa應(yīng)用程序中的每個(gè)線程都維護(hù)自己的Autorelease Pool Block堆棧。如果您正在編寫一個(gè)只有Foundation-only的程序妓局,或者如果分離一個(gè)線程(沒(méi)有使用GCD或者NSThread),則需要?jiǎng)?chuàng)建自己的Autorelease Pool Block好爬。
如果您的應(yīng)用程序或線程壽命很長(zhǎng),并且可能生成大量自動(dòng)釋放的對(duì)象存炮,則應(yīng)該使用自動(dòng)釋放池塊(如AppKit和UIKit在主線程上做);否則穆桂,自動(dòng)釋放的對(duì)象會(huì)積累宫盔,內(nèi)存占用空間也會(huì)增加享完。如果分離的線程不進(jìn)行Cocoa調(diào)用,則不需要使用自動(dòng)釋放池塊般又。
四、NSCopying
NSCOpying協(xié)議聲明了一種提供對(duì)象功能副本的方法茴迁。
“副本”的確切含義可能因類而異,但副本必須是一個(gè)功能獨(dú)立的對(duì)象堕义,其值與復(fù)制時(shí)的原始值相同热某。
用NSCOpying制作的副本由發(fā)送者隱式保留,發(fā)送者負(fù)責(zé)釋放它。
聲明一個(gè)方法昔馋,copyWithZone:,但是復(fù)制通常使用方便方法副本調(diào)用糖耸。復(fù)制方法是為所有NSOBjects定義的秘遏,并簡(jiǎn)單地調(diào)用具有默認(rèn)區(qū)域的copyWithZone:。