對 block 記憶體管理的一些看法

來源:互聯網
上載者:User

標籤:

首先交代一下retain cycle ,和 產生retain cycle後我們應該怎麼處理。

1.retain cycle在block中是極易產生,block就是一段可以靈活使用的代碼,你可以把它當做變數傳遞,賦值,甚至可以把它聲明到函數體中。更加靈活的是它可以引用它的承載著(即就是block的運行環境),但是這樣子就更容易產生retain cycle了 。就是簡單說類比 子控制項擁有父控制項的引用,而父控制項也擁有子控制項的引用。這樣相互引用。就不能形成父控制項釋放也能將子控制項釋放。這就造成一個記憶體泄露。

2.及時打破這種retain cycle ARC :__strong , __weak ,__unsafe_unretained.存在有三個修飾字元,__strong 這要有調用,引用計數就要加1(retain) __unsafe_unretained 賦值給這個變數不會被retain,就是有這個字元修飾的對象,不能保證對象的可靠性。可能已經釋放了。留下的只是一個野指標而已。__weak是ios5以後出現的類比與__unsafe_unretained,不同的地方就是。它所持有對象被釋放後會自動被賦值為nil。更加安全了。

正如下面的代碼就是一個典型的retain cycle    

People *p=[People new];

    p.dosth = ^(){

        [p dosth];

        [p release]; //因為dosth和p是相互持有關係,所以調用release也不能釋放掉

    };

1.我們可以這樣子處理(自己心裡應該清楚,我們不會再次回來調用這個方法了)

People *p=[People new];

    p.dosth = ^{

        [p dosth];

        p.dosth=nil;

        [p release]; //因為dosth和p是相互持有關係,所以調用release也不能釋放掉

    };

2.在ARC情況下

 在ARC下, 以下幾種情況, Block會自動被從棧複製到堆:

     1.被執行copy方法

     2.作為方法傳回值

     3.將Block賦值給附有__strong修飾符的id類型的類或者Blcok類型成員變數時

     4.在方法名中含有usingBlock的Cocoa架構方法或者GDC的API中傳遞的時候.

利用

__block 將變數的地址考進了棧空間,這樣子我們就可以在Block中方便無比的調用最新的變數值了。因為block的空間也是在棧空間的.block記憶體是在棧上,(不需要程式員管理),當你這個範圍{方法}結束的時候,block被釋放了.

 __weak 被__weak修飾的變數,是不會被block retain的,但是也會同時引出提前釋放變數的後果

3.在非ARC情況下

只要實現一個對周圍變數沒有引用的Block,就會顯示為是NSGlobalBlock  

如果其中加入了對局部變數的引用,就是NSStackBlock   

如果你對一個NSStackBlock對象使用了Block_copy()或者發送了copy訊息,就會得到NSMallocBlock  (0)

1)NSGlobalBlock:retain、copy、release操作都無效;

2)NSStackBlock:retain、release操作無效,必須注意的是,NSStackBlock在函數返回後,Block記憶體將被回收。即使retain也沒用。容易犯的錯誤是[mutableAarry addObject:stackBlock],(補:在ARC中不用擔心此問題,因為ARC中會預設將執行個體化的Block拷貝到堆上)在函數出棧後,從mutableAarry中取到的stackBlock已經被回收,變成了野指標。正確的做法是先將[stackBlock copy]到堆上,然後加入數組:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支援copy,copy之後產生新的NSMallocBlock類型對象。

3)NSMallocBlock支援retain、release,雖然retainCount始終是1,但記憶體管理器中仍然會增加、減少計數。copy之後不會產生新的對象,只是增加了一次引用,類似retain;

4)Block_copy與copy等效,Block_release與release等效;

5)對Block不管是retain、copy、release都不會改變引用計數retainCount,retainCount始終是1;

6)盡量不要對Block使用retain操作,不方便管理。

4、Block對objc對象的記憶體管理

staticObj、instanceObj、localObj、blockObj多種類型obj對象

主要是block被copy時其塊中用到的變數的引用計數

1)非ARC

staticObj在記憶體中的位置是確定的,所以Block copy時引用計數不會改變。

instanceObj在Block copy時並沒有直接讓instanceObj對象本身引用計數加1,但卻讓self引用計數加1。所以在Block中可以直接讀寫instanceObj變數。 

localObj在Block copy時,系統自動增加其引用計數。

blockObj在Block copy時引用計數也不會改變。

使用__block避免循環參考

__block 類 *對象 = self

void(^block)(void)= ^{

[blockSelf doSomething];

};

ARC下

只有在使用local變數時,block會複製指標,且強引用指標指向的對象一次。其它如全域變數、static變數、block變數等,block不會拷貝指標,只會強引用指標指向的對象一次。

block的循環參考,因為block在拷貝到堆上的時候,會retain其引用的外部變數,那麼如果block中如果引用了它的宿主對象,那很有可能引起循環參考。如:

self.myblock = ^{

[self doSomething];

};

使用__weak避免循環參考

 

Tips:

記憶體主要分為

1.棧 - 由編譯器自動分配釋放  裡面的變數通常是局部變數 函數參數等

2.堆 - 一般由程式員分配釋放,若程式員不釋放,程式結束時可能由OS回收 alloc

3.全域區(靜態區 static),全域變數和靜態變數的儲存是放在一塊的,初始化的全域變數和靜態變數在一塊地區,未初始化的全域變數和未初始化的靜態變數在相鄰的另一塊地區。- 程式結束釋放 static

People *p;  People *p2 = nil;

4.另外還有一個專門放常量的地方。- 程式結束釋放  NSString *lastName = @“xue”;

lastName = @“dkjs”;

5、方法區

對 block 記憶體管理的一些看法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.