iOS 內(nèi)存管理機(jī)制

最近接手的一個(gè) APP 項(xiàng)目有內(nèi)存泄露問(wèn)題, 由于用了 ARC 管理內(nèi)存, 使得找出哪里內(nèi)存泄露了變得更加困難, 找了一下午, 終于使得幾個(gè)控制器對(duì)象得到釋放.

從最簡(jiǎn)單的 c 語(yǔ)言開始說(shuō)起, c 語(yǔ)言中申請(qǐng)(malloc)到了一塊內(nèi)存, 你可以把這塊內(nèi)存想象成一個(gè)小球, 你有根線牽著它, 這根線就是指針, 并且規(guī)定只有通過(guò)線才能拿到小球, 一個(gè)小球可以被很多人用線牽著.
c 語(yǔ)言中釋放內(nèi)存, 就相當(dāng)于把小球直接銷毀, 但可能還有其他人用線牽著這個(gè)小球啊, 當(dāng)你釋放之后, 別人用這個(gè)線就找不到這個(gè)小球了, 所以別人的線就成為了"野指針", 就不安全了

然后到了 oc 中的管理內(nèi)存, 同樣把內(nèi)存比作小球, 你申請(qǐng)一塊內(nèi)存的時(shí)候還是由一根線牽著小球, 但是釋放的時(shí)候, 就不讓你直接銷毀那個(gè)小球, oc 會(huì)給每個(gè)小球做個(gè)數(shù)量標(biāo)記, 這個(gè)標(biāo)記記錄著有幾根線牽著它! 當(dāng)有n根線牽著它的時(shí)候, 這個(gè)標(biāo)記為 n, 你要釋放內(nèi)存的時(shí)候, oc 會(huì)把標(biāo)記的數(shù)量減1, 記得 oc 并不會(huì)像 c 語(yǔ)言一樣立刻釋放內(nèi)存, 它只是把標(biāo)記的數(shù)量減1而已, 直到標(biāo)記的數(shù)量減為0了, oc 才會(huì)去釋放掉那塊內(nèi)存.

知道了原理, 再來(lái)看看 oc 的 MRC 內(nèi)存管理機(jī)制
如果兩個(gè)對(duì)象直接復(fù)制 obj1 = obj2, 此時(shí) obj1 和 obj2 指向同一塊內(nèi)存, 那塊內(nèi)存的計(jì)數(shù)為 1, 有兩個(gè)指針指著那內(nèi)存, 按道理說(shuō)應(yīng)該要是 2 才對(duì)啊, 如果要使得那塊內(nèi)存計(jì)數(shù)為 2, 應(yīng)該這樣寫
obj1 = [obj2 retain]; 要加 retain 關(guān)鍵字, 讓內(nèi)存計(jì)數(shù)器+1, 這樣那塊內(nèi)存的計(jì)數(shù)才是 2, 此時(shí)兩個(gè)指針指著同一塊內(nèi)存!, 修改了 obj1 的內(nèi)容, obj2 也會(huì)被修改
釋放的時(shí)候 [obj2 release]; release 關(guān)鍵字, 讓內(nèi)存計(jì)數(shù)器-1, 不一定會(huì)釋放那塊內(nèi)存, 記得只有減為 0 了才會(huì)被釋放, 此時(shí) 還有 obj1 指著那塊內(nèi)存吧, 所以內(nèi)存并沒(méi)有釋放,

如果我想修改 obj1 不影響 obj2 的話, 應(yīng)該使用 copy 關(guān)鍵字, 像這樣
obj1 = [obj2 copy]; 此時(shí) obj1 和 obj2 指著兩塊不同的內(nèi)存, 每塊內(nèi)存的計(jì)數(shù)都是 1, 那么修改 obj1 內(nèi)容就不會(huì)影響到 obj2 的內(nèi)容了
還有最重要的就是用完了內(nèi)存要記得 release 釋放掉, 不然內(nèi)存會(huì)一直占用著, 浪費(fèi)空間, 有個(gè)原則, 誰(shuí)創(chuàng)建的誰(shuí)釋放, 不要你創(chuàng)建的, 我來(lái)釋放, 這樣程序復(fù)雜了會(huì)亂的, 造成內(nèi)存泄露.

當(dāng)程序代碼變多了, 每次寫 alloc, release, 很累人, 而且很可能忘記寫! 造成內(nèi)存泄露, 為了解決這個(gè), oc 推出了 ARC 內(nèi)存管理機(jī)制, 叫做自動(dòng)引用計(jì)數(shù), 不用再寫 release 這樣容易忘記寫的語(yǔ)句了, oc 會(huì)在編譯期間, 在合適的地方, 自動(dòng)給你插入這樣的釋放語(yǔ)句, 使程序員輕松了很多.
ARC 中多了幾個(gè)關(guān)鍵字
weak, weak 不會(huì)使得對(duì)象的計(jì)數(shù)器+1, 也就是說(shuō), 一個(gè) weak 的指針, 留不住一個(gè)對(duì)象
strong, strong 才會(huì)使得對(duì)象計(jì)數(shù)器+1, 當(dāng)一個(gè)對(duì)象有 strong 的指針指著時(shí), 它不會(huì)被釋放, 當(dāng)沒(méi)有 strong 指針指著時(shí)才會(huì)被釋放掉, 并且把那些指向它的 weak 指針全部置為 nil, 避免了野指針的出現(xiàn).

ARC 的引進(jìn)減輕了程序員負(fù)擔(dān), 但是又導(dǎo)致了更難排查的"內(nèi)存循環(huán)引用"問(wèn)題
我說(shuō)說(shuō)原理, 當(dāng)一個(gè)對(duì)象有 strong 指針指著的時(shí)候, 就不會(huì)被釋放, 那如果 有兩個(gè)對(duì)象互相指著對(duì)方,
就像 A->B, B->A, 兩個(gè)對(duì)象指針形成了一個(gè)環(huán), 這種情況就誰(shuí)都無(wú)法釋放了, 如果有 n 個(gè)對(duì)象之間形成了環(huán), 那么就更難查了, 還記得圖論當(dāng)中的拓?fù)渑判騿? 拓?fù)渑判蚩梢杂脕?lái)檢測(cè)圖中的環(huán), 理論上編譯器可以在編譯期就告訴我們是否發(fā)生了內(nèi)存循環(huán)引用.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容