對 block 內存管理的一些見解

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

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];spa

        [p release]; //由於dosth和p是相互持有關係,因此調用release也不能釋放掉指針

    };對象

1.咱們能夠這樣子處理(本身內心應該清楚,咱們不會再次回來調用這個方法了)ip

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操做,不方便管理。

四、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」;

五、方法區

相關文章
相關標籤/搜索