本文章將記錄Objective-C中內(nèi)存管理的相關(guān)資料,如有錯誤歡迎指出~
iOS的內(nèi)存管理一般指的是OC對象的內(nèi)存管理纳决,因為OC對象分配在堆內(nèi)存,堆內(nèi)存需要程序員自己去動態(tài)分配和回收;基礎(chǔ)數(shù)據(jù)類型(非OC對象)則分配在棧內(nèi)存中,超過作用域就會由系統(tǒng)檢測回收缨伊。如果我們在開發(fā)過程中,對內(nèi)存管理得不到位进宝,就有可能造成內(nèi)存泄露刻坊。
Objective-C中提供了兩種內(nèi)存管理機(jī)制:MRC(MannulReference Counting)和 ARC(Automatic Reference Counting),MRC指的是手動內(nèi)存管理党晋,在開發(fā)過程中需要開發(fā)者手動去編寫內(nèi)存管理的代碼紧唱;ARC指的是自動內(nèi)存管理活尊,在此內(nèi)存管理模式下由LLVM編譯器和OC運行時庫生成相應(yīng)內(nèi)存管理的代碼。
引用計數(shù)
不管是MRC 還是 ARC 漏益,都是通過對引用計數(shù)來進(jìn)行內(nèi)存管理的。
- 創(chuàng)建一個新對象的時候深胳,它的引用計數(shù)為 1
- 當(dāng)有一個新的指針指向這個對象時绰疤,其引用計數(shù)加 1
- 當(dāng)某個指針不再指向這個對象是,其引用計數(shù)減 1舞终,當(dāng)對象的引用計數(shù)變?yōu)?0 時轻庆,說明這個對象不再被任何指針指向了,這個時候就可以將對象銷毀敛劝,回收內(nèi)存余爆。
當(dāng)一個對象使用完沒有釋放,此時其引用計數(shù)永遠(yuǎn)大于1夸盟。該對象就會一直占用其分配在堆內(nèi)存的空間蛾方,就會導(dǎo)致內(nèi)存泄露。內(nèi)存泄露到一定程度有可能導(dǎo)致內(nèi)存溢出上陕,進(jìn)而導(dǎo)致程序崩潰桩砰。
MRC(MannulReference Counting)
先了解下 內(nèi)存管理的思想
- 自己生成的對象,自己持有释簿。
- 非自己生成的對象亚隅,自己也能持有。
- 不再需要自己持有的對象時釋放對象庶溶。
- 非自己持有的對象無法釋放煮纵。
從上面的思想來看,我們對對象的操作可以分為三種:創(chuàng)建偏螺,持有行疏,釋放,再加上廢棄砖茸,一共有四種隘擎。它們所對應(yīng)的Objective-C的方法和引用計數(shù)的變化是:
對象操作 | Objecctive-C方法 | 引用計數(shù)的變化 |
---|---|---|
生成并持有對象 | alloc/new/copy/mutableCopy等方法 | +1 |
持有對象 | retain方法 | +1 |
釋放對象 | release方法 | -1 |
廢棄對象 | dealloc方法 | 無 |
ARC (Automatic Reference Counting)
在ARC機(jī)制下,編譯器就可以自動進(jìn)行內(nèi)存管理凉夯,減少了開發(fā)的工作量货葬。但是仍有一些問題需要我們?nèi)プ⒁狻?/p>
循環(huán)引用(Reference Cycle)問題
引用計數(shù)這種管理內(nèi)存的方式雖然很簡單,但是有一個比較大的瑕疵劲够,即它不能很好的解決循環(huán)引用問題震桶。如下圖所示:
- 對象 A 和對象 B,相互引用了對方作為自己的成員變量征绎,只有當(dāng)自己銷毀時蹲姐,才會將成員變量的引用計數(shù)減 1磨取。
- 因為對象 A 的銷毀依賴于對象 B 銷毀,而對象 B 的銷毀與依賴于對象 A 的銷毀柴墩,這樣就造成了我們稱之為循環(huán)引用(Reference Cycle)的問題
- 這兩個對象即使在外界已經(jīng)沒有任何指針能夠訪問到它們了忙厌,它們也無法被釋放。
不止兩對象存在循環(huán)引用問題江咳,多個對象依次持有對方逢净,形式一個環(huán)狀,也可以造成循環(huán)引用問題歼指,而且在真實編程環(huán)境中爹土,環(huán)越大就越難被發(fā)現(xiàn)。下圖是 4 個對象形成的循環(huán)引用問題踩身。
那該怎么解決循環(huán)引用的問題呢赛蔫?使用弱引用 (weak reference) 的辦法牺勾。
弱引用
使用弱引用來持有對象讯泣,弱引用雖然持有對象嗦枢,但是并不增加引用計數(shù),這樣就避免了循環(huán)引用的產(chǎn)生赁濒。
在 iOS 開發(fā)中轨奄,弱引用通常在 delegate 模式中使用。舉個例子來說拒炎,
- 兩個 ViewController A 和 B挪拟,ViewController A 需要彈出 ViewController B,讓用戶輸入一些內(nèi)容击你,當(dāng)用戶輸入完成后玉组,ViewController B 需要將內(nèi)容返回給 ViewController A。
- 這個時候丁侄,View Controller 的 delegate 成員變量通常是一個弱引用惯雳,以避免兩個 ViewController 相互引用對方造成循環(huán)引用問題,
弱引用的實現(xiàn)原理是:
- 系統(tǒng)對于每一個有弱引用的對象鸿摇,都維護(hù)一個表來記錄它所有的弱引用的指針地址石景。
- 當(dāng)一個對象的引用計數(shù)為 0 時,系統(tǒng)就通過這張表拙吉,找到所有的弱引用指針潮孽,繼而把它們都置成 nil。
面試題
面試題請參考 這篇文章 iOS 內(nèi)存管理相關(guān)面試題