IOS 記憶體管理

2021-06-22 06:05:14 字數 4615 閱讀 8974

範圍:

任何繼承了nsobject的物件,對基本資料型別無效

原理:每個物件內部都儲存了乙個與之相關聯的整數,稱為引用計數器

當使用alloc、new或者copy建立乙個物件時,物件的引用計數器被設定為1

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

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

當乙個物件的引用計數器值為0時,那麼它將被銷毀,其占用的記憶體被系統**,oc也會自動向物件傳送一條dealloc訊息。一般會重寫dealloc方法,在這裡釋放相關資源。一定不要直接呼叫dealloc方法

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

1.誰建立,誰釋放(「誰汙染,誰治理」)。如果你通過alloc、new或(mutable)copy來建立乙個物件,那麼你必須呼叫release或autorelease。換句話說,不是你建立的,就不用你去釋放

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

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

#import

#import "book.h"

@inte***ce student

@property book *book;

@end

#import "student.h"

@implementation student 

@synthesize book = _book;

- (void)setbook:(book *)book

}- (void)dealloc

@end

通常引用乙個類有兩種辦法:

一種是通過#import方式引入;

一種是通過@class引入

兩種方式的區別:

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

2、使用@class方式由於只需要知道被引用類(b類)的名稱就可以了,而在實現類由於要用到被引用類中的實體變數和方法,所以在.m檔案中需要使用#import來包含被引用類的標頭檔案

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

#import

@class book;

@inte***ce student

@property (retain) book *book;

@end

#import "student.h"

#import "book.h"

@implementation student 

//@synthesize會自動展開setter和getter, 隱藏了記憶體管理細節

@synthesize book = _book;

- (void)dealloc

@end

自動釋放池是oc裡面的一種記憶體自動**機制,一般可以將一些臨時變數新增到自動釋放池中,統一**釋放

當自動釋放池銷毀時,池裡面的所有物件都會呼叫一次release方法

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

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

ios 5.0後

@autoreleasepool

ios 5.0前

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

// .....

[pool release]; // 或[pool drain];

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

[student setbook:book];

[book release];

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

[student setbook:book];

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

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

+(id)book

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

在iphone專案中,main()中有乙個預設的autorelease pool,程式開始時建立,程式退出時銷毀,按照對autorelease的理解,豈不是autorelease pool裡的所有物件在程式退出時才release,這樣跟記憶體洩露有什麼區別?

對於每乙個runloop, 系統會隱式建立乙個autorelease pool,並且把建立好的pool放在棧頂,所有的pool會構成乙個棧式結構。在每乙個runloop結束時,當前棧頂的pool會被銷毀,這樣這個pool裡的每個物件會執行release操作

在arc下,不能使用[[nsautoreleasepool alloc] init],而應當使用@autoreleasepool

不要把大量迴圈操作放到同乙個nsautoreleasepool之間,這樣會造成記憶體峰值的上公升

盡量避免對大記憶體使用該方法,對於這種延遲釋放機制,還是盡量少用

sdk中一般利用靜態方法建立並返回的物件都是已經autorelease的,不需要再進行release操作

如[nsnumber numberwithint:10];返回的物件是不需要再release的。

但是通過[[nsnumber alloc] initwithint:10]建立的物件需要release

格式:@property(引數1,引數2)型別 名字;

引數可有可無, 比如:

@property int age;

@property(nonatomic,retain) uibutton* btn;

引數主要分為3類

讀寫屬性:readwrite/readonly

setter處理:assign/retain/copy

原子性:atomic/nonatomic

@property屬性預設為atomic,提供多執行緒安全

在多執行緒環境下,原子操作是必要的,否則有可能引起錯誤的結果

加了atomic,setter/getter是乙個原子操作。如果有多個執行緒同時呼叫setter的話,不會出現某乙個執行緒執行setter全部語句之前,另乙個執行緒開始執行setter的情況,相當於函式頭尾加了鎖一樣

禁止多執行緒,變數保護,提高效能

atomic是oc使用的一種執行緒保護技術,防止在寫入未完成的時候被另外乙個執行緒讀取,造成資料錯誤。而這種機制是耗費系統資源的,所以在iphone這種小型裝置上,如果沒有使用多執行緒間的通訊程式設計,那麼nonatomic是乙個非常好的選擇

如果不需要多執行緒支援的話,用nonatomic就夠了,另外由於不涉及鎖操作,所以它執行相對快點

readwrite: 產生setter\getter

readonly: 只產生簡單的getter,沒有setter。

assign: 預設型別,setter方法直接賦值,而不進行retain操作

retain: setter方法release舊值,再retain新值

copy: setter方法release舊值,再copy新值

分析下面一種情景:(假設都是retain引用)

物件a引用了物件b,物件b引用了物件c,物件c引用了物件b.

這時候b和c的引用計數分別是2和1.當a不再使用b,呼叫release釋放對b的所有權,因為c還引用了b,所以b的引用計數為1,b不會被釋放。b不釋放,c的引用計數就是1,c也不會被釋放。從此,b和c永遠留在記憶體中

為了打斷上面這種迴圈引用,b和c互相引用時,應該一端使用ratain,另一端使用assign

arc,就是由編譯器**中自動加入了

retain/release

。要注意的是,

arc並不是

gc,它只是一種**靜態分析工具 從

ios 5/mac os x 10.7

開始匯入,利用

xcode4.2

可以使用該機制

優點:不需要擔心煩人的記憶體管理和記憶體洩露

**的總量變少了

**效率高,由於使用編譯器管理引用計數,減少了低效**的可能性

缺點:要記住新的

arc規則、關鍵字、特性

使用一些舊**、第三方**的時候比較麻煩,可能要修改編譯開關,

xcode4.2

中預設arc

是yes

的狀態retain, release, autorelease, dealloc由編譯器自動插入,不能在**中呼叫

dealloc雖然可以被過載,但是不能呼叫[super dealloc]

不能使用nsautoreleasepool,應該使用@autoreleasepool塊

不能使用」new」開頭的屬性名稱

ios記憶體管理

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

iOS記憶體管理

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

IOS 記憶體管理

ios記憶體管理一直是頭疼的問題,有時間做些簡單的筆記 使用assign 對基礎資料型別 nsinteger cgfloat 和c 資料型別 int,float,double,char,等等 使用copy 對 nsstring 使用 retain 對其他 nsobject 和其子類 lnonatom...