垃圾回收:
垃圾回收指的是程序運行過程中,檢查是否有不再使用的對象,并自動釋放他們所占用的內(nèi)存锄开,通常被簡稱為GC。內(nèi)存的檢查和回收都是由垃圾收集器完成的称诗。
在OC2.0中萍悴,垃圾回收首先進(jìn)行的工作就是識別不允許被回收的對象。全局變量寓免,靜態(tài)變量和棧內(nèi)臨時變量他們所引用的對象不允許被回收癣诱。這些對象稱為根集合。如果一個對象的實例變量引用了不允許被回收的對象或根集合中的對象袜香,那么這個對象也不允許被回收撕予。也就是說,通過全局變量蜈首,靜態(tài)變量或者棧內(nèi)變量的強(qiáng)引用而查找到的對象都不可以被回收实抡。反之,只要是從根集合出發(fā)無法到達(dá)的對象都屬于垃圾回收的目標(biāo)欢策。
對于不再使用的對象我們可以通過為其賦值nil來明確表示其已不再被使用吆寨,據(jù)此通知垃圾收集器回收該對象。這種做法不僅有助于垃圾回收猬腰,也是一種良好的編程風(fēng)格鸟废。
垃圾收集器整個回收過程完全是根據(jù)程序占用內(nèi)存的多少自動完成的。一個程序只有一個垃圾收集器姑荷,通常在mainthread中運行盒延。它通常作為一個單獨的線程運行。垃圾收集器運行的時候有可能會暫停其他線程來完成垃圾收集鼠冕。
主動啟動垃圾回收:通過給類NSGarbageCollector發(fā)送collectIfNeeded消息來啟動垃圾收集器添寺。通過主動啟動垃圾回收,不僅可以控制內(nèi)存消費懈费,又可以避免垃圾回收突然啟動時程序反應(yīng)變慢的問題计露。
finalize方法的定義:
finalize方法被定義在NSObject中,在對象被回收之前憎乙,finalize方法會被執(zhí)行票罐。原則上不推薦輕易定義finalize,因為finalize方法作為垃圾回收的一部分被執(zhí)行泞边,垃圾回收在一個獨立的線程中進(jìn)行该押。同軟件本身是并行關(guān)系,如果finalize處理過于復(fù)雜的話就會影響軟件本身的執(zhí)行速度阵谚。另外蚕礼,要被釋放的對象的finalize方法的執(zhí)行是沒有先后順序的烟具。不要依賴finalize方法的執(zhí)行順序來做任何事情。
實現(xiàn)finalize方法的時候要注意下面這些事項:
finalize方法內(nèi)不用擔(dān)心其他對象的釋放奠蹬。
要注意finalize方法中對象的賦值朝聋。
finalize的執(zhí)行順序和對象的釋放順序都是無法確定的。
finalize不是線程安全的囤躁。
對象的善后處理應(yīng)該在這個對象不再使用的時候進(jìn)行冀痕,而不要在finalize 方法中進(jìn)行。特別是文件之類的資源對象狸演,不要在finalize方法中進(jìn)行關(guān)閉處理金度。進(jìn)行善后處理之后,可以將不再使用的對象賦值為別的對象或者nil严沥,以取消對該對象的引用猜极,并告知垃圾收集器該對象可以被清理了。
反之消玄,在多個地方釋放對象時跟伏,就不得不用到finalize方法。
使用垃圾回收編程小結(jié):
·編譯的時候需要使用編譯選項fobjc-gc-only
·使用局部變量給方法中的局部對象賦值
·如果暫時不想垃圾回收某對象翩瓜,需要保證該對象能夠被全局變量引用
·原則上垃圾回收只負(fù)責(zé)回收id類型或類類型的變量
·不用考慮所有權(quán)的問題受扳,也不用考慮實例變量的問題
·釋放對象時的一些“善后”操作可以寫在finalize方法中,但除了不寫在finalize中就無法實
現(xiàn)的功能兔跌,要盡量減少通過finalize完成的操作
·引用計數(shù)相關(guān)的方法和dealloc方法不會被執(zhí)行
分代垃圾回收:
啟用垃圾回收后勘高,會在變量賦值,改寫變量時建立寫屏障坟桅。OC2.0利用修改變量時的信息采用分代垃圾回收的方式來進(jìn)行內(nèi)存管理华望。分代垃圾回收并不會每次對整個堆空間進(jìn)行遍歷,而是以新生成的對象為中心仅乓,以盡可能快速的收集那些生命周期短的對象赖舟,通過這種分代的方法,既可以減輕垃圾回收的處理負(fù)荷夸楣,又能有效釋放空間宾抓,但也要小心這種方法會積攢太多的陳舊對象。
弱引用:
和ARC不一樣的是豫喧,棧內(nèi)的臨時變量不能聲明為弱引用石洗。同時也可以使用_ _ strong修飾符來聲明一個變量是強(qiáng)引用類型。除了這兩個修飾符外紧显,_ _autoreleasing和_ _unsafe_unretained等其他生命期修飾符在垃圾回收中都不可用讲衫。
弱引用的作用在于解決強(qiáng)引用所帶來的對象之間在存活時間上的耦合關(guān)系。
盡量不要使用這種依賴于垃圾回收的運行頻率和時機(jī)的編程方法鸟妙。
通過垃圾回收回收動態(tài)分配的內(nèi)存:
通過NSAllocateCollectable()分配的內(nèi)存因為可以通過垃圾回收被自動回收焦人,所以可以不考慮內(nèi)存釋放的問題,比使用malloc和free編程更方便重父。但指向初對象之外的動態(tài)內(nèi)存的指針變量都需要用_ _strong來修飾花椭。另外,程序的效率有可能會降低房午,所以并不需要特意把原來使用的malloc/free的代碼都改為NSAllocateCollectable矿辽。
_ _ strong修飾符的使用方法:
修飾對象類型的變量。
修飾指針類型的變量郭厌。被_ _strong修飾的指針?biāo)赶虻膬?nèi)存可以被垃圾回收袋倔,但要等到該指針不再使用為止。
用于修飾函數(shù)或方法返回的指針類型折柠。指針指向的內(nèi)存屬于垃圾回收的范疇宾娜,但如果被賦值給一個強(qiáng)引用類型的變量,就暫時不能被回收扇售。
NSGarbageCollector類:
+ (id)defaultCollector ?//返回現(xiàn)在有效的垃圾收集器的實例前塔,如果垃圾收集無效,則返回nil承冰。
- (void)collectIfNeeded //申請進(jìn)行垃圾回收华弓。這個方法被調(diào)用之后會判斷當(dāng)前內(nèi)存使用情況,如果覺得需要進(jìn)行垃圾回收就會啟動垃圾收集器困乒。典型的調(diào)用方式如下:
[[NSGarbageCollectordefaultCollector]collectIfNeeded];
- (void)collectExhaustively //申請進(jìn)行垃圾回收寂屏。希望使用深度遍歷以盡可能地釋放更多的內(nèi)存時使用。這個方法被調(diào)用之后會判斷當(dāng)前內(nèi)存使用情況娜搂,如果覺得需要進(jìn)行垃圾回收就會啟動垃圾收集器迁霎。
- (void)disableCollectorForPointer:(void *)ptr //調(diào)用這個函數(shù)之后,這個指針?biāo)赶虻膬?nèi)存不會被回收百宇。也就是說指針指向的對象會變成根集合中的對象欧引。如果想讓對象變?yōu)榭梢员辉俅位厥盏脑挘枰{(diào)用下面的enableCollectorForPointer:
- (void)enableCollectorForPointer:(void *)ptr //能夠讓通過disableCollectorForPointer:指定不允許被釋放的內(nèi)存或?qū)ο笤俅卧试S被釋放恳谎。
- (void)enable
- (void)disable //disable方法能讓垃圾收集器暫時停止內(nèi)存回收芝此。enable方法則能讓垃圾收集器恢復(fù)工作。但enable和disable不許成對使用因痛。這兩個函數(shù)一般被用于防止多線程中同時運行垃圾回收婚苹。
- (BOOL)isEnabled //用于判斷垃圾回收器是否有效,有效時返回真鸵膏。
實時API:
控制垃圾回收器的動作膊升。
void objc_startCollectorThread (void); //啟動一個線程專門運行垃圾收集器。
oid *objc_memmove_collectable(void *dst, const void *src, size_t size); //復(fù)制垃圾回收對象的內(nèi)存時使用該函數(shù)替代memcpy和memmove谭企。
內(nèi)存管理方式的比較:
首先讓我們來看看和手動內(nèi)存管理相比廓译,ARC和垃圾回收有哪些優(yōu)點评肆。
·不需要再在意對象的所有權(quán)
·可以刪除程序中內(nèi)存管理部分的大部分代碼,使程序看起來更清爽
·可以避免手動內(nèi)存管理時的錯誤(內(nèi)存泄漏等)
·不需要再在意引用計數(shù)內(nèi)存管理中的一些特殊用法非区。例如訪問方法的定義和臨時對象的使用等
·可以使多線程環(huán)境下的編程更簡單瓜挽。例如:不用擔(dān)心不同的線程之間可能出現(xiàn)的所有權(quán)沖突
垃圾回收的缺點如下所示。
·垃圾收集器運行時會影響程序的速度
·需要不停地監(jiān)視內(nèi)存的使用征绸,同引用計數(shù)的方法相比久橙,程序的速度會變慢
·會影響程序的效率。不經(jīng)常使用的內(nèi)存也會被垃圾收集器不時地訪問管怠,實際上有可能會占用
更多的內(nèi)存
·需要使用一些技巧來讓對象被回收或不被回收
·無法使用引用計數(shù)管理方式下的一些設(shè)計方針淆衷。例如:事先準(zhǔn)備好一些管理文件或其他資源類的對象,在對象被釋放的同時關(guān)閉資源
相比較而言渤弛,ARC沒有垃圾回收那么多缺點祝拯,但也有一些要注意的地方
·循環(huán)引用一旦形成就不會自己消失
·為了防止循環(huán)引用的形成,需要注意對象間的關(guān)系她肯。GUI的各個類之間也有可能形成循環(huán)引
用鹿驼,也要注意防止循環(huán)引用的形成
·理論上可被賦值的對象都可以被自動釋放,但在處理結(jié)構(gòu)體辕宏、數(shù)組畜晰、二重指針等類型的變量
時有一些限制
·需要注意Core Foundation的對象和Objectve-G的對象之間的轉(zhuǎn)換(詳情請參考附錄B)
更改內(nèi)存管理方式:
與對象的所有權(quán)和生存期相關(guān)的處理
釋放對象之后的善后處理
防止野指針的生成
有時還需要從對象之間的相互關(guān)系來重新考慮