iOS 記憶體管理簡單介紹

2021-07-02 18:34:39 字數 4035 閱讀 4791

1. 什麼是記憶體管理

➢ 管理範圍:任何繼承了nsobject的物件,對其他基本資料型別(int、char、float、double、struct、enum等)無效。

2. 物件的基本結構

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

➢ 每個oc物件內部專門有4個位元組的儲存空間來儲存引用計數器

3. 引用計數器的作用

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

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

➢當計數器為0時則不能呼叫release或者retain count,否則引起crash。

4. 引用計數器的操作

➢ 給物件傳送一條retain訊息,可以使引用計數器值+1(retain方法返回物件本身)

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

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

5. 物件的銷毀

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

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

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

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

➢ 不要直接呼叫dealloc方法。

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

誰建立,誰release

➢ 如果你通過alloc、new或[mutable]copy來建立乙個物件,那麼你必須呼叫release或autorelease

➢ 換句話說,不是你建立的,就不用你去[auto]release

誰retain,誰release

➢ 只要你呼叫了retain,無論這個物件是如何生成的,你都要呼叫release

總結

➢ 有始有終,有加就有減

➢ 曾經讓物件的計數器+1,就必須在最後讓物件計數器-1

set方法記憶體管理

比如有個book *_book

1. set方法的實現

- (void)setbook:(book *)book

} 2. dealloc方法的實現

- (void)dealloc

@property引數

1. 控制set方法的記憶體管理

➢ retain : release舊值,retain新值(用於oc物件)

➢ assign : 直接賦值,不做任何記憶體管理(預設,用於非oc物件型別)

➢ copy : release舊值,copy新值(一般用於nsstring *)

2. 控制需不需生成set方法

➢ readwrite :同時生成set方法和get方法(預設)

➢ readonly :只會生成get方法

3. 多執行緒管理

➢ atomic :效能低(預設)

➢ nonatomic :效能高

4. 控制set方法和get方法的名稱

➢ setter : 設定set方法的名稱,一定有個冒號:

➢ getter : 設定get方法的名稱

迴圈引用

1. @class

➢ 使用場景 對於迴圈依賴關係來說,比方a類引用b類,同時b類也引用a類 這種**編譯會報錯。當使用@class在兩個類相互宣告,就不會出現編譯報錯

➢ 用法概括 使用

@class 類名; 就可以引用乙個類,說明一下它是乙個類

➢ 和#import的區別

 #import方式會包含被引用類的所有資訊,包括被引用類的變數和方法;@class方式只是告訴編譯器在a.h檔案中 b *b 只是類的宣告,具體這個類裡有什麼資訊,這裡不需要知道,等實現檔案中真正要用到時,才會真正去檢視b類中資訊

 如果有上百個頭檔案都#import了同乙個檔案,或者這些檔案依次被#improt,那麼一旦最開始的標頭檔案稍有改動,後面引用到這個檔案的所有類都需要重新編譯一遍,這樣的效率也是可想而知的,而相對來 講,使用@class方式就不會出現這種問題了

 在.m實現檔案中,如果需要引用到被引用類的實體變數或者方法時,還需要使用#import方式引入被引用類

2. 迴圈retain

➢ 比如a物件retain了b物件,b物件retain了a物件

➢ 這樣會導致a物件和b物件永遠無法釋放

3. 解決方案

➢ 當兩端互相引用時,應該一端用retain、一端用assign

autorelease

1. autorelease

➢ 給某個物件傳送一條autorelease訊息時,就會將這個物件加到乙個自動釋放池中。

➢ 當自動釋放池銷毀時,會給池子裡面的所有物件傳送一條release訊息。

➢ 呼叫autorelease方法時並不會改變物件的計數器,並且會返回物件本身。

➢ autorelease實際上只是把對release的呼叫延遲了,對於每一次autorelease,系統只是把該物件放入了當前的。autorelease pool中,當該pool被釋放時,該pool中的所有物件會被呼叫release。

2. 自動釋放池的建立

➢ ios 5.0後

@autoreleasepool

➢ ios 5.0前

nsautoreleasepool *pool = [[nsautoreleasepool alloc] init];

// .....

[pool release];

// 或[pool drain];

➢ 在程式執行過程中,可以建立多個自動釋放池,它們是以棧的形式存在記憶體中

➢ oc物件只需要傳送一條autorelease訊息,就會把這個物件新增到最近的自動釋放池中(棧頂的釋放池)

3. 應用例項

➢ 跟release的對比

 以前: book *book = [[book alloc] init];

[book release];

 現在: book *book = [[[book alloc] init] autorelease];

// 不要再呼叫[book release];

➢ 一般可以為類新增乙個快速建立物件的類方法

+ (id)book

外界呼叫[book book]時,根本不用考慮在什麼時候釋放返回的book物件

4. 規律

➢ 一般來說,除了alloc、new或copy之外的方法建立的物件都被宣告了autorelease。

➢ 比如下面的物件都已經是autorelease的,不需要再release。

nsnumber *n = [nsnumber numberwithint:100];

nsstring *s = [nsstring stringwithformat:@"jack"];

nsstring *s2 = @"rose";

ios記憶體管理

引用計數 每個物件有乙個與之相關的整數,稱作 引用計數器 或者 保留計數器 當某段 需要訪問乙個物件時,該段 會將物件的保留計數器 1,表示需要訪問這個物件 當結束對該物件的訪問時,保留計數器 1,表示它不在訪問該物件 當保留計數器為0時,物件被銷毀,所佔記憶體被系統收回。當使用new retain...

iOS記憶體管理

前提 1 以下是針對cocoa物件,不包括core foundation 2 cocoa物件都是用引用計數來跟蹤物件的記憶體使用情況的。3 在子類裡面父類先初始化和後釋放的原則。自己想下為什麼 棧空間和堆空間的區別。我們說的記憶體管理都是基於堆空間的,因為函式內的棧空間是由編譯器自己控制的。關於co...

IOS 記憶體管理

範圍 任何繼承了nsobject的物件,對基本資料型別無效 原理 每個物件內部都儲存了乙個與之相關聯的整數,稱為引用計數器 當使用alloc new或者copy建立乙個物件時,物件的引用計數器被設定為1 給物件傳送一條retain訊息,可以使引用計數器值 1 給物件傳送一條release訊息,可以使...