iOS 基本記憶體管理 引用計數器

2021-06-21 02:55:02 字數 3574 閱讀 5793

**:

1.什麼是記憶體管理

系統會發出記憶體警告,這時得**一些不需要再使用的記憶體空間。比如**一些不需要使用的物件、變數等

管理範圍:任何繼承了nsobject的物件需要去管理記憶體,但是對於對其他基本資料型別(int、char、float、double、struct、enum等)結構,列舉等不用去關心記憶體

複製**

- (void)test

複製**

一旦test方法執行完畢,意味著區域性變數的作用域也失效,那麼棧空間的區域性變數系統會自動檢測**。但是堆空間中動態產生的物件是還沒有被**。如圖

可以看出即使已經沒有指標指向動態產生的物件了,但還是沒有被**,因此需要手動管理釋放。釋放的方法是為物件傳送一條訊息。因此需要呼叫物件的某個方法來釋放物件。

那麼系統是怎麼知道此時的物件需不需要**呢?這就涉及到了物件結構中的"引用計數"

2.物件結構

每個oc物件內部都有自己的引用計數器,它是乙個整數,表示"物件被引用的次數",即有多少人正在使用這個oc物件

每個oc物件內部會自動設定4個位元組的儲存空間來儲存引用計數器

3.引用計數器的作用

當使用alloc、new或者copy建立乙個新物件時,新物件的引用計數器預設就是1

當乙個物件的引用計數器值為0時,物件占用的記憶體就會被系統**。換句話說,如果物件的計數器不為0,那麼在整個程式執行過程,它占用的記憶體就不可能被**,除非整個程式已經退出

4.操作物件引用計數器的方法

給物件傳送一條retain訊息,可以使引用計數器值+1(retain方法返回物件本身)retain方法返回的是id型別,那麼哪個物件呼叫返回的就是自己

給物件傳送一條release訊息,可以使引用計數器值-1

可以給物件傳送retaincount訊息獲得當前的引用計數器值

5.物件的銷毀

當乙個物件的引用計數器值為0時,那麼它將被銷毀,其占用的記憶體被系統**

當乙個物件被銷毀時,系統會自動向物件傳送一條dealloc訊息

一般會重寫dealloc方法,在這裡釋放相關資源,dealloc就像物件的遺言

一旦重寫了dealloc方法,就必須呼叫[super dealloc],並且放在最後面呼叫

不能直接呼叫dealloc方法

一旦物件被**了,它占用的記憶體就不再可用,堅持使用會導致程式崩潰(野指標錯誤)

複製**

// alloc方法是給堆中分配記憶體 init方法和記憶體無關 此時retaincurrent為1

person *p = [[person alloc] init];

// 返回的就是物件本身 retaincurrent為2

[p retain];

// retaincurrent為1

[p release];

// retaincurrent為0 說明person類物件被**,那麼對應的在記憶體中的位址已經不可用了 此時的person物件稱為「殭屍物件」但是此時p指標還是在指向person類物件所對應的那塊不可用的位址此時的p指標稱為「野指標」

[p release];

複製**

6.開發中要注意的記憶體管理

預設情況下,xcode是不會管理殭屍物件的,即使使用了一塊被釋放的記憶體也不會報錯。為了方便除錯,應該開啟殭屍物件監控。如圖設定:

注意三個概念:

殭屍物件:已經被**的物件,或者說物件所對應的記憶體位址已經不可用的物件稱為殭屍物件。殭屍物件不可用

野指標:指向一塊不可用記憶體位址或者指向殭屍物件的指標稱為野指標。給野指標傳送訊息會報 exc_bad_access錯誤

空指標:沒有指向任何指標變數稱為空指標,也意味著指標變數所儲存的值為0,nil,null 這樣可以避免野指標錯誤的發生

複製**

/********************************** person.h **************************************/

#import

@inte***ce person : nsobject

@property int age;

@end

/********************************** person.m **************************************/

#import "person.h"

@implementation person

// 重寫父類nsojbct的遺言方法 物件在被釋放之前一定會呼叫dealloc方法

- (void)dealloc

@end

/********************************** main.m **************************************/

#import

#import "person.h"

/* main方法是乙個死迴圈方法以保證程式能持續執行,除非使用者關閉程式或者是手機沒電,程式才能終止

那麼在main方法裡面的person物件不就一直存在麼,因此必須在main方法裡面將物件**

*/int main(int argc, const char * argv)

{// alloc方法是給堆中分配記憶體 init方法和記憶體無關 此時retaincurrent為1

person *p = [[person alloc] init];

// 返回的就是物件本身 retaincurrent為2

[p retain];

// retaincurrent為1

[p release];

/* retaincurrent為0

說明person類物件被**,那麼對應的在記憶體中的位址已經不可用了 

此時的person物件稱為「殭屍物件」

此時p指標還是在指向person類物件所對應的那塊不可用的位址,此時p指標稱為「野指標」

*/[p release];

/*物件已經被**,千萬別以為再給物件傳送乙個retain訊息物件就可以「起死回生」應該節哀順變

執行retain方法會報錯,此時的p指標已稱為野指標執行**回報:野指標錯誤

*/// [p retain];

/*此時物件已經被**稱為「殭屍物件了」不可以再訪問屬性

在執行p.age = 10;報錯:

-[person setage:]: message sent to deallocated instance  訊息傳送給了已經被釋放的物件

再次證明「殭屍物件不可以用」

*//* 

一旦指標成為野指標再繼續向p指標所指的物件傳送訊息就會報錯:exc_bad_access

說明訪問了一塊壞記憶體(已經被**、不可用的記憶體) 「野指標錯誤」 

那麼此時在物件**之後將指標變數清空

那麼棧中的指標變數就不會再指向堆中類物件的記憶體位址了

*/p = nil;

/*  

指標變數內部所儲存的值已被清空,那麼指標已經無指向

再給指標傳送任何訊息指標會無任何響應,而且也不報錯因為oc中沒有空指標錯誤

*/[p release];

[p release];

[p release];

[p release];

return 0;

引用計數器 與 記憶體管理

一 引用計數器的基本操作 1.方法的基本使用 1 retain 計數器 1,會返回物件本身 2 release 計數器 1,沒有返回值 3 retaincount 獲取當前的計數器的值 4 dealloc 當乙個person物件被 的時候,就會自動呼叫這個方法 void dealloc 2.概念 1...

自動引用計數器 一

自動引用計數器是指記憶體管理中引用採取自動計數的計數。一.記憶體管理的思考方式 思考方式分為四類 1.自己生成的物件,自己所持有。2.非自己生成的物件,自己也能持有。3.不在需要自己持有的物件時候釋放。4.非自己持有的物件無法釋放。生成並持有物件 alloc new copy mutablecopy...

記憶體管理之引用計數

在一些開發語言中,記憶體管理使用的是引用計數的方法,比如python objc等。採用引用計數,開發人員不需要管理記憶體,能夠從記憶體管理繁瑣的工作中脫離出來,從而將更多的精力花費在開發程式上。引用計數的原理 python和objc中的每個物件內部都維護著乙個引用計數器,當新建乙個物件,或者有其他物...