block 記憶體管理

2021-09-24 06:31:24 字數 2500 閱讀 5408

block簡介(copy一段)

block作為c語言的擴充套件,並不是高新技術,和其他語言的閉包或lambda表示式是一回事。需要注意的是由於objective-c在ios中不支援gc機制,使用block必須自己管理記憶體,而記憶體管理正是使用block坑最多的地方,錯誤的記憶體管理 要麼導致return cycle記憶體洩漏要麼記憶體被提前釋放導致crash。 block的使用很像函式指標,不過與函式最大的不同是:block可以訪問函式以外、詞法作用域以內的外部變數的值。換句話說,block不僅 實現函式的功能,還能攜帶函式的執行環境。

可以這樣理解,block其實包含兩個部分內容

block執行的**,這是在編譯的時候已經生成好的;

乙個包含block執行時需要的所有外部變數值的資料結構。block將使用到的、作用域附近到的變數的值建立乙份快照拷貝到棧上。

block與函式另乙個不同是,block類似objc的物件,可以使用自動釋放池管理記憶體(但block並不完全等同於objc物件,後面將詳細說明)。

block的型別與記憶體管理

根據block在記憶體中的位置分為三種型別nsglobalblock,nsstackblock, nsmallocblock。

nsglobalblock:類似函式,位於text段;(一直存在,可以用,只有在執行完才釋放)

nsstackblock:位於棧記憶體,函式返回後block將無效;

nsmallocblock:位於堆記憶體。(需要使用自動釋放或者手動釋放)對nsstackblock 進行copy就是nsmallocblock

block的copy、retain、release操作

nsglobalblock:retain、copy、release操作都無效:nsstackblock:retain、release操作無效,必須注意的是,nsstackblock在函式返回後,block記憶體將被**。即使retain也沒用。容易犯的錯誤是[[mutableaarry addobject:stackblock],(補:在arc中不用擔心此問題,因為arc中會預設將例項化的block拷貝到堆上)在函式出棧後,從mutableaarry中取到的stackblock已經被**,變成了野指標。正確的做法是先將stackblock copy到堆上,然後加入陣列:[mutableaarry addobject:[[stackblock copy] autorelease]]。支援copy,copy之後生成新的nsmallocblock型別物件。

nsmallocblock支援retain、release,雖然retaincount始終是1,但記憶體管理器中仍然會增加、減少計數。copy之後不會生成新的物件,只是增加了一次引用,類似retain

結果是 只有區域性變數引用計數加一,block copy 是不建立新物件;

__globalobj和__staticobj在記憶體中的位置是確定的,所以block copy時不會retain物件。

_instanceobj在block copy時也沒有直接retain _instanceobj物件本身,但會retain self。所以在block中可以直接讀寫_instanceobj變數。

localobj在block copy時,系統自動retain物件,增加其引用計數。

blockobj在block copy時也不會retain。

迴圈引用retain cycle

迴圈引用指兩個物件相互強引用了對方,即retain了對方,從而導致誰也釋放不了誰的記憶體洩露問題。如宣告乙個delegate時一般用assign而不能用retain或strong,因為你一旦那麼做了,很大可能引起迴圈引用。在以往的專案中,我幾次用動態記憶體檢查發現了迴圈引用導致的記憶體洩露。

這裡講的是block的迴圈引用問題,因為block在拷貝到堆上的時候,會retain其引用的外部變數,那麼如果block中如果引用了他的宿主物件,那很有可能引起迴圈引用,如:

self.myblock = ^{

[self dosomething];

總結:1.預設情況下, block的記憶體是在棧中(nsstackblock

*它不會對所引用的物件進行任何操作

2.如果對block做一次copy操作, block的記憶體就會在堆中(nsmallocblock

* 它會對所引用的物件做一次retain操作

* 非arc : 如果所引用的物件用了__block修飾, 就不會做retain操作

* arc : 如果所引用的物件用了__unsafe_unretained\__weak修飾, 就不會做retain操作

3.修改外部引用時, block變數,被__block修飾的變數稱作block變數。 基本型別的block變數等效於全域性變數、或靜態變數,可以在block內部修改,不會拷貝乙份。非block變數,在block內使用不能修改,內部是對外部的拷貝,外部修改也不影響內部的使用。

block的記憶體管理

block的記憶體管理 block變數是儲存在棧記憶體中的,所以宣告屬性時,應該使用copy屬性,將其複製到堆記憶體中。block在dealloc中釋放時,使用函式 block release 假如在customview中宣告了乙個block,在customviewcontroller中建立了乙個c...

Block 記憶體管理原則

今天在寫 的時候,遇到了block一直exc bad access的問題,之前一直覺得block應該像int一樣直接assign就可以,不會存在記憶體的問題,今天查了資料才知道block是繼承自nsobject的,一樣有記憶體問題,特此記錄一下。block記憶體管理的規則 1,block指標會在方法...

iOS的block記憶體管理

初始情況下 block本身 block修飾的變數以及在block內部使用的變數都是在棧裡的。block修飾的變數的位址會作為實參傳入block塊內部 暫時先這麼理解,實際比較複雜 block使用的外部變數被const拷貝到了block內部。也就是block使用的外部變數和這個外部變數本身沒有關係。c...