內存管理(一) - 引用計數式的理解

CSDN地址

有道地址

概要


OC中的內存管理,也就是引用計數。可以用開關燈房間的案例來說明:

假設辦公室照明設備只有一個。上班的人進入辦公室需要照明,所以把燈打開。而隊對於下班離開辦公室的人來說,已經不需要照明瞭,所以把等關掉。若是很多上下班,每個人都開燈或者關燈,那麼辦公室的情況又將如何呢?最早下班的人關燈,那麼辦公室豈不是一片黑暗。

解決這個問題的辦法是使辦公室還有至少一個人的情況下保持開燈狀態,無人的時候保持關狀態。
1. 最早進入辦公室開燈
2. 之後進入辦公室的人,需要照明
3. 下班離開辦公室的人,不需要照明
4. 最後離開辦公室的人關燈(此時已無人需要照明)

根據計數功能來計算 ”需要照明的人數”

  1. 第一個人進入辦公室,辦公室的計數爲1。計數:1
  2. 之後進入辦公室的人,疊加1。計數:2
  3. 每當人有人下班離開,減去1。計數:1
  4. 最後離開辦公室,減去1。計數:0,因此要關燈。

在OC中,”對象” 相當於辦公室的照明設備。

  1. 開燈 –> 生成對象
  2. 需要照明 –> 持有對象
  3. 不再需要照明 –> 釋放對象
  4. 關燈 –> 廢棄對象

內存管理的思考方式


  • 自己生成並持有對象。
  • 持有非自己生成的對象。
  • 不再需要自己持有的對象時釋放。
  • 非自己持有的對象無法釋放。
對象操作 Objective-C方法
生成並持有對象 alloc/new/copy/muetableCopy等方法
持有對象 retain 方法
釋放對象 release 方法
廢棄對象 dealloc 方法

自己生成並持有對象

下面寫出了自己生成並持有對象,我們使用alloc方法:

<!--自己生成並持有對象-->
id obj = [[NSObject alloc] init];

copy方法利用基於NSCopying方法約定,由各類實現copyWithZone:方法生成並持有對象的副本。與Copy方法類似,mutableCopy方法利用基於NSMutableCopying方法約定,由各類實現mutableCopyWhitZone:方法生成持有對象的副本。

這些方法生成的對象,雖然是對象的副本,但同alloc、new方法一樣,在 “自己生成並持有對象” 這點上沒有改變。

所謂自己生成,這個自己可以看做當前環境或者編程人員本身也沒錯。或者可以這樣理解,當前這個對象是在當前的環境生成,那麼這個對象就屬於這個當前環境生成的,所以對象被當前環境持有。

結論:

通過alloc/new/copy/mutableCopy生成的對象都是 自己生成並持有對象

持有非自己生成的對象

<!--取得非自己生成並持有的對象-->
id obj = [NSMutableArray array];

上述源碼中,NSMutableArray類對象被賦給變量obj,但變量obj自己並不持有改對象。使用retain方法可以持有對象。

//持有對象
[obj retainl];

後續會說明爲什麼這種方式(非alloc/new/copy/mutableCopy)生成的就是非自己生成的。

不再需要自己持有的對象時釋放

自己持有的對象,一旦不再需要,持有者有義務釋放該對象。釋放使用release方法。

//自己生成並持有對象
id obj = [[NSObject alloc] init];

//釋放
[obj release];

自己生成並持有 和 非自己生成也能持有 的原理。

alloc/new/copy/mutableCopy 方法生成 自己生成並持有的對象,或者用 retain 方法持有的對象,一旦不再需要,務必要用 release 方法進行釋放。

現在我們通過源碼來分析:爲什麼會有自己生成並持有非自己生成也能持有 :

  1. 通過模擬 alloc/new/copy/mutableCopy 方法, 理解 自己生成並持有對象
+ (NSObject *) allocObject {
    //自己生成並持有對象
    id obj = [[NSObject alloc] init];
    //自己持有對象
    retain obj;
}

原封不動地返回用 alloc 方法生成並持有對象,就能讓調用方也持有該對象。

<!--取得非自己生成並持有的對象-->
id obj1 = [NSObject allocObject];

allocObject 與用 alloc方法生成並持有對象的情況完全相同,所有使用allocObject方法也就意味着 自己生成並持有對象

  1. 通過模擬 [NSMutableArray array] 方法, 理解 非自己生成並持有對象

前面就有說到調用 [NSMutableArray array] 方法使取得的對象存在,但是自己又不持有對象,又是怎麼實現的呢?

- (id)object {

    //自己生成並持有對象
    id  obj =  [[NSObject alloc] init];

    //使對象在超出指定的生成範圍時能夠自動並正確地的釋放
    [obj autorelease];

    //返回對象
    return obj;
}

上例中,我們使用了 autorelease 方法。用該方法,可以使取得的對象存在,但是自己不持有對象。

這樣的好處就是,我們可以不用去手動去管理通過此方法 生成的對象 的釋放。

autorelease 提供這樣的功能,是對象在超出指定的生成範圍時能夠自動並正確地釋放(調用release方法)

release 和 autorelease 的區別

看完這張 release 和 autorelease 圖:

相信大家已經明白爲什麼通過objectarray方法生成的是非自己生成,是因爲生成在生成這個對象的方法裏面,添加延遲釋放處理,而不需要我們再去調用release釋放了。

那麼我們要如何去區分到底誰需要調用release,誰不需要調用release。所以引入了命名規則:

  • 使用NSMutableArray類的array類方法等可以取得誰都不持有的對象,這些方法都是通過 autorelease 而實現的
  • alloc/new/copy/mutableCopy 方面名開頭的,就是 自己生成並持有的對象

無法釋放非自己持有的對象

alloc/new/copy/mutableCopy 方法生成 自己生成並持有的對象,或者用 retain 方法持有的對象,一旦不再需要,務必要用 release 方法進行釋放。

而由此以外所得到的對象絕對不能釋放。倘若在應用程序中釋放了非自己所持有的對象會造成崩潰。

例如自己生成並持有對象後,在釋放完後,再次釋放。(重複調用release);

或者是在 “取得對象的存在,但是自己不持有對象” 時釋放。

都會到導致應用程序崩潰!因此絕對不要釋放非自己持有的對象!

以上五項內容,就是 “引用計數式內存管理” 的思考方式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章