Obj C記憶體管理(二)

2021-07-04 08:12:08 字數 4551 閱讀 5293

autorelease的本質就是呼叫 nsautoreleasepool的addobject方法

//imp caching 方法呼叫的實現

id autorelease_class = [nsautoreleasepool class];

sel autorelease_sel = @selector(addobject:);

imp autorelease_imp = [autorelease_class methodforselector:autorelease_sel];

- (id)autorelease

objc4/runtime/objc-arr.mm class autoreleasepoolpage — 陣列的autorelease實現

class autoreleasepoolpage

static

inline

void *pop( void *token)

static

inline

void *autorelease(id obj)

id *add(id obj)

id *releaseall()

};void *objc_autoreleasepoolpush(void)

void objc_autoreleasepoolpop(void *ctxt)

id *objc_autorelease(id obj)

//下面我們對照nsautoreleasepool的使用及其對應runtime實現

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

/* 等同於呼叫 objc_autoreleasepoolpush */

id obj = [[nsobject alloc] init];

[obj autorelease];

/*等同於 obj_autorelease(obj)*/

[pool drain];

/*等同於呼叫 objc_autoreleasepoolpop(pool)*/

tips:我們可通過nsautoreleasepool除錯用非公開方法 「showpools」來確認已被autorelease的物件的狀況,單此方法只能在ios中使用,在執行的除錯中,我們使用 「_objc_autoreleasepoolprint()」方法作為替代。

//函式宣告

//extern void _objc_autoreleasepoolprint();

// //autoreleasepool 除錯用輸出開始

//_objc_autoreleasepoolprint();

__autoreleasing 修飾符與__strong一樣,一般不會顯式使用。在取得非自己生成並持有的物件時,雖然可以使用 「alloc/new/copy/mutablecopy」但是,該物件已經被註冊到了autoreleasepool中,這同在arc無效時取得了呼叫了autorelease方法的物件是一樣的。這是由於編譯器會檢查方法名是否以 「alloc/new/copy/mutablecopy」開始,如果不是,則自動將返回值的物件註冊到autoreleasepool。另外,init方法建立的物件不會註冊到 autoreleasepool 中。

以 「alloc/new/copy/mutablecopy」取得的物件屬於自己生成並持有的,其原始碼如下。

在非arc中,nsautoreleasepool是不能使用的,我們使用@autoreleasepool{}來代替。

@autoreleasepool

+ (id)array

//obj修飾符為__strong在超出其作用域後會被自動釋放,但是作為該方法的返回值,根據其方法名,編譯器會自動將其註冊到autoreleasepool中。

物件的指標

nserror * error = nil;

bool result = [obj performoperationwitherror:&error];

方法宣告:

- (bool)performoperationwitherror(nserror **)error;
實際上物件的指標會自動附加上__autoreleasing修飾符,所以該方法宣告等同於

- (bool)performoperationwitherror(nserror * __autoreleasing *)error

因為宣告為nserror * __autoreleasing * 型別的 error作為 *error被賦值,所以方法呼叫結束後,error的持有者依舊存在,所以可以得到正常的返回值.

tips: 「@autoreleasepool」在巢狀使用時,總是使用最內層的「@autoreleasepool」。

tips:__strong 和 __weak 修飾符的變數類似於 c++ 的智慧型指標 std::shared_ptr 和 std::weak_ptr。std::shared_ptr 可以通過引用計數來持有c++例項,std::weak_ptr可以避免造成迴圈引用。

arc規則

1.不能使用 retain/release/retaincount/autorelease

2.不能使用 nsallocateobject/nsdeallocateobject

3.遵守記憶體管理方法的命名規則

4.不要顯式呼叫 dealloc

5.使用 @autoreleasepool 代替 nsautoreleasepool

6.不能使用區域(nszone)

7.物件型別不能作為 c 語言結構體 (struct/union) 的成員

8.顯式轉換 「id」和「void *」

1~6條比較簡單,不做過多介紹,著重介紹第七第八條

7.物件型別不能作為 c 語言結構體成員

c語言的規約上沒有方法來管理結構體成員變數的生存週期。因為在arc中是由編譯器來管理記憶體的,所以編譯器必須知道並管理物件的生存週期。例如 c 語言的區域性變數可使用變數的作用域來管理變數的生存週期。但是對於 c 語言的結構體成員來說,這在標準上就是不可實現的。詳情請戳:結構體。所以,當我們要把物件型變數加入結構體中時,可以強制轉換為void*(具體參見第八條)或附加 __unsafe_unretained 修飾符。因為附有 __unsafe_unretained 的變數不屬於編譯器的記憶體管理物件,所以使用時必須格外注意賦值物件的所有者,稍不注意就會導致記憶體洩露和程式崩潰。

8.顯示轉換「id」和「void*」

我們先來觀察arc無效時的轉換。

id obj = [[nsobject alloc] init];

void * p = obj;

id o = p;

[o release];//即使呼叫由「void *」賦值的「id」變數的例項方法也不會出問題。

若轉化為arc有效的話需要使用 __bridge

id obj = [[nsobject alloc] init];

void * p = (__bridge void *) obj;

id o = (__bridge id)p;

但是實際上使用__bridge的變數的安全性類似或者說甚至低於__unsafe_unretained修飾的變數型別,所以只要稍不注意賦值物件的所有者就會產生懸垂指標並導致程式崩潰。

所以我們常用的兩種轉換分別是 __bridge_retained 和 __bridge_transfer。

__bridge_retained會使要被轉換賦值的物件也持有該物件,如果按照上例的話其效果相當於

/* __bridge_retained 轉換*/

void * p = (__bridge_retained void *)obj;

/*arc無效*/

id obj = [[nsobject alloc] init];

void * p = obj;

[(id)p retain];

__bridge_transfer則提供與__bridge_retained相反的動作,使要被轉換賦值的物件持有該物件後,釋放該物件轉換之前的持有者,如果按照上例的話其效果相當於

/* __bridge_retained 轉換*/

void * p = (__bridge_transfer void *)obj;

/*arc無效*/

id obj = [[nsobject alloc] init];

void * p = obj;

[(id)p retain];

[obj release];

tips:以上提到的兩種轉換多用於轉換 fundation (obj-c) 框架和 core fundation (c) 框架,兩者的實際差別很小,並且任何框架生成的物件都可相互使用,持有,釋放。且這種轉換不需要使用額外的cpu資源,所以也稱為「免費橋(toll-free bridge)」(toll-free bridge url).

objc 記憶體管理

1.在oc中,物件也具有生命週期。其也有產生 生存 接受訊息和執行操作 交友 借助方法的組合和引數 死去等屬性。2.cocoa採用引用計數 reference counting 技術,來判斷該物件是否達到生命週期終結。當某段 需要訪問乙個物件時,該物件的reference counting 加一,當...

objc記憶體管理

一 記憶體管理規則 1 對於通過呼叫帶有alloc copy mutablecopy new或者create一詞的方法建立的任何物件及其記憶體,你都擁有所有權。你負責在之後的某個時刻向該物件傳送release訊息來釋放資源。使用類似 foo alloc init.命令建立的物件需要釋放。任何使用類似...

記憶體管理二

發現兩篇記憶體池的博文,博文位址如下,寫的很好,能避免記憶體碎片和記憶體洩露問題,比我這個玩具 要好很多,大家可以看看 在我們做專案的時候,經常會分配了記憶體,然後卻忘了釋放,造成記憶體洩漏的問題。以下 可以實現在 退出的時候自動釋放之前申請但未釋放的記憶體。其原理是 用乙個雙向鍊錶維護申請的記憶體...