ARC記憶體管理機制詳解

青玉伏案發表於2015-12-19

ARC在OC裡面個人感覺又是一個高大上的牛詞,在前面Objective-C中的記憶體管理部分提到了ARC記憶體管理機制,ARC是Automatic Reference Counting—自動引用計數。有自動引用計數,那麼就得有手動引用計數MRC(Mannul Reference Counting),前面已經提到過了MRC。那麼在ARC模式下是不是意味著我們就可以一點也不用進行記憶體管理的呢?並不是這樣的,我們還需要程式碼進行記憶體的管理。下面會結合著程式碼把OC中的ARC機制做一個詳細的總結(歡迎大家批評指標,轉載請註明出處 )。

在ARC機制下是少不了下面這些東西的:

1.關鍵字 __strong  預設值,表示只要有強引用指標指向該變數,則該變數會一直存在。

2.關鍵字__weak 弱引用,表示若沒有任何強引用指標指向該變數,會自動將變數的值置為空,即nil狀態。

3.關鍵字 __autoreleasing 用於標示自動釋放的變數

4.__unsafe_unretained 不安全的弱引用,若沒有任何強引用指標指向該變數,不會自動設為空,會成為野指標。

關於Weak和Strong,看下圖吧:

第一次接觸ARC的小夥伴們看到上面的概念可能會一頭霧水,上面說的是個啥?都是哪跟哪?不用著急,下面會有例項程式碼,結合著例項程式碼,然後再做一個總結,你就會有種豁然開朗的感覺。你就會明白,哦,原來ARC是這麼一回事。好啦,廢話少說,用程式碼講東西才是王道,程式碼走起。(為了方便我們觀察記憶體的釋放情況,可以設定斷點來單步執行)

為了做測試使用,我們建一個測試類,並重寫dealloc方法來觀察記憶體的釋放情況,測試類如下;

一.__strong:  強引用,是ARC中變數宣告的預設值,用大白話講就是你手動分配的堆記憶體,如果沒有指標指向這塊記憶體,那麼這塊記憶體就會被回收

1.當宣告變數為強引用時,物件的指標出棧時,如果該指標指向的記憶體空間沒有別的指標指向他,就自動掉用dealloc方法釋放堆記憶體測試程式碼如下:

程式碼執行結果:

程式碼說明:從執行結果來看,出程式碼塊後我們定於的指標變數會隨著我們程式碼塊的結束而釋放,就沒有指標指向我們分配的堆記憶體了,以為預設為strong,所以在ARC機制下會立即呼叫dealloc來釋放堆記憶體。

2.給物件指標重寫分配記憶體的情況,程式碼如下:

程式碼執行結果:

程式碼說明:我們先給strong型別的物件指標分配記憶體空間,然後再次分配記憶體空間,在第二次分配空間的時候,就沒有物件指標指向原有的記憶體空間,所以在第二次分配空間之後就會把原有的記憶體空間給釋放掉,在出程式碼塊的時候,物件指標也會隨著棧記憶體的釋放而釋放掉,也沒有物件指標指向第二次分配的記憶體了,所以會被釋放掉。

 3.把物件指標置為空時,分配的堆記憶體會立即被釋放掉。相應的程式碼如下:

程式碼執行結果:

程式碼說明:把指向該記憶體空間的物件指標置空,就相當於沒有指標指向該記憶體空間,所以在strong下會被立即釋放。

4.把新的物件指標指向堆記憶體空間,然後把原有的指標進行置空

程式碼如下:

執行結果:

程式碼說明:當兩個指標同時指向一塊記憶體空間時,把原有的指標置為空,這塊記憶體空間不會被釋放的,因為還有其他的指標指向該記憶體空間。

二. __weak 歸零弱引用:在若指標指向的記憶體被釋放後,若引用的指標則會置零

歸零弱引用:弱引用的指標指向強引用的記憶體時,是不影響其釋放記憶體空間的,當弱引用指標所指空間被釋放掉得時候,該弱引用指標會被置零。

程式碼如下

執行結果如下:

程式碼說明:當出大括號時強引用指標會被釋放掉,之前開闢的堆記憶體空間只有一個弱引用指標指向他,所以在ARC中會被自動釋放,弱引用指標會置零。

三. __autoreleasing 自動釋放,一般結合著@autoreleasepool使用。

 1.自動釋放修飾的指標所指向的記憶體空間會在自動釋放池結束的時候會被釋放,程式碼如下

程式碼執行結果:

程式碼說明:自動釋放池結束後,自動物件指標指向的記憶體空間會被釋放,但上面的用法會產生野指標。

2.__autoreleasing結合著自動釋放池會延遲記憶體空間的釋放

程式碼如下:

執行結果:

程式碼說明:由執行結果可以看出即使把指向記憶體空間的自動釋放型別的指標置空,其對應的記憶體空間不像強引用那樣被直接釋放掉,而是等到自動釋放池結束後在釋放,這就是延遲釋放。

3.被自動釋放型別的指標用過的記憶體空間,在自動釋放池結束的時候一樣會被釋放掉。

程式碼如下:

程式碼執行結果:

程式碼說明:上面的程式碼可能會引起記憶體洩露,因為如果第一次分配空間的時候如果我們往物件里加入的是一個視訊,那麼在第二次給自動釋放型別的指標分配記憶體的時候,前面的記憶體空間不會被釋放掉,直到自動釋放池結束後兩個記憶體空間才會被釋放掉。

四,strong, autoreleasing,weak混在一起的使用情況

在weak中的例子,我們能得到weak和strong同指向一塊記憶體空間,當strong的指標不指向該記憶體空間時,這塊記憶體空間就可以被釋放掉,而weak指標被置零。

記憶體空間只要有autoreleasing或者strong的指標所持有,就不會被釋放

1.strong和autoreleasing的混用

(1).strong型別的指標指向自動釋放的空間

程式碼如下:

執行結果如下:

執行結果說明:上面是先讓自動釋放型別的指標指向該記憶體空間,然後再使強型別的指標指向該記憶體空間,在出自動釋放池的時候是不會釋放該記憶體空間的,直到強引用指標被釋放掉,才釋放該記憶體空間。

(2).自動釋放型別的指標指向strong型別的指標所分配的空間的情況

程式碼執行結果:

結果說明:當strong修飾的指標隨著棧的釋放而釋放,但其指向的記憶體空間並沒有被釋放,因為他還被自動釋放型別的指標所持有,所以在出自動釋放池的時候才會被釋放。

(3).strong 型別的指標會指向自動釋放型別的空間記憶體,當strong指標被置空時該記憶體不會被釋放。

程式碼如下:

​程式碼執行結果:

2.弱型別和自動釋放型別的混用

程式碼如下:

程式碼執行結果:

程式碼說明:即使有弱引用型別的指標指向該記憶體空間在出自動釋放池的時候,該記憶體空間也會被釋放。弱引用的指標會被置零。

上面寫了這麼多來點總結性的東西吧:strong 修飾的指標指向的空間如果沒有其他指標就會被釋放掉(weak型別的不算), 自動釋放型別的指標如果沒有其他型別的指標指向該記憶體空間時,當自動釋放池結束後就會釋放。

上面的總結暫且這麼說吧,是根據筆者自己的理解所總結的內容,不免有偏頗之處,歡迎批評指正,轉載請註明出處。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

ARC記憶體管理機制詳解

相關文章