1. 程式人生 > >block與堆疊的恩怨情仇

block與堆疊的恩怨情仇

一、block放在哪裡

我們針對不同情況來討論block的存放位置:

1.棧和堆

以下情況中的block位於堆中:

  1. void foo()  
  2. {  
  3.     __block int i = 1024;  
  4.     int j = 1;  
  5.     void (^blk)(void);  
  6.     void (^blkInHeap)(void);  
  7.     blk = ^{ printf("%d, %d\n", i, j);};//blk在棧裡 
  8.     blkInHeap = Block_copy(blk);//blkInHeap在堆裡 
  9. }  
  10. - (void)fooBar  
  11. {  
  12.     _oi = 1;  
  13.     OBJ1* oj = self;  
  14.     void (^oblk)(void) = ^{ printf("%d\n", oj.oi);};  
  15.     void (^oblkInHeap)(void) = [oblk copy];//oblkInHeap在堆中 

2.全域性區

以下情況中的block位於全域性區:

  1. staticint(^maxIntBlock)(intint) = ^(int a, int b){return a>b?a:b;};  
  2. - (void)fooBar  
  3. {  
  4.      int(^maxIntBlockCopied)(intint) =[maxIntBlock copy];  
  5. }  
  6. void foo()  
  7. {  
  8.      int(^maxIntBlockCopied)(intint) = Block_copy(maxIntBlock);  

需要注意的是,這裡複製過後的block依舊位於全域性區,實際上,複製操作是直接返回了原block物件。

二、block引用的變數在哪裡

 1.全域性區

全域性區的變數儲存位置與block無關:

  1. staticint gVar = 0;  
  2. //__block static int gMVar = 1; 
  3. void foo()  
  4. {  
  5.     staticint stackVar = 0;  
  6. //    __block static int stackMVar = 0; 

注意:static變數是不允許新增__block標記的

2.堆疊

此時,你可能會問,當函式foo返回後,棧上的j已經回收,那麼blkInHeap怎麼能繼續使用它?這是因為沒有__block標記的變數,會被當做實參傳入block的底層實現函式中,當block中的程式碼被執行時,j已經不是原來的j了,所謂物是人非就是這樣吧~

另外,如果使用到變數j的所有block都沒有被複制至heap,那麼這個變數j也不會被複制至heap。

因此,即使將j++這一句放到blk()這句之前,這段程式碼執行後,控制檯列印結果也是:1024, 1。而不是1024, 2

三、其他特性

1.複製的行為

對block呼叫複製,有以下幾種情況:

1.對全域性區的block呼叫copy,會返回原指標,並且這期間不處理任何東西(至少目前的內部實現是這樣);

2.對棧上的block呼叫copy,每次會返回新複製到堆上的block的指標,同時,所有__block變數都會被複制至堆一份(多次拷貝,只會生成一份)。

3.對已經位於heap上的block,再次呼叫copy,只會增加block的引用計數。

為什麼我們不討論retian的行為?原因是並沒有Block_retain()這樣的函式,而且objc裡面的retain訊息傳送給block物件後,其內部實現是什麼都不做。

2.objc類中的block複製

objc類例項方法中的block如果被複制至heap,那麼當前例項會被增加引用計數,當這個block被釋放時,此例項會被減少引用計數。

但如果這個block沒有使用當前例項的任何成員,那麼當前例項不會被增加引用計數。這也是很自然的道理,我既然沒有用到這個instance的任何東西,那麼我幹嘛要retian它?

我們要注意的一點是,我看到網上有很多人說block引起了例項與block之間的迴圈引用(retain-cycle),並且給出解決方案:不直接使用self而先將self賦值給一個臨時變數,然後再使用這個臨時變數。

但是,大家注意,我們一定要為這個臨時變數增加__block標記(多謝第三篇文章回帖網友的提醒)。

這一章我們以結果導向的方式來說明了各種情況下,block的記憶體問題,下一章,我將剖析執行時庫的原始碼,從根源闡述block的行為。也就是過程導向的方式了。

相關推薦

block堆疊恩怨情仇

一、block放在哪裡 我們針對不同情況來討論block的存放位置: 1.棧和堆 以下情況中的block位於堆中: void foo()  {      __block int i = 1024;      int j = 1;      void (^blk)(v

CSS魔法堂:display:nonevisibility:hidden的恩怨情仇

前言  還記得面試時被問起"請說說display:none和visibility:hidden的區別"嗎?是不是回答完display:none不佔用原來的位置,而visibility:hidden保留原來的位置後,面試官就會心一笑呢?其實不止那麼簡單呢!本文我們將一起深究它倆的恩怨情仇,下次面試時我們可以回答

程序建立fork()的恩怨情仇

一、述說程序: 1、程序(process)是個什麼? 狹義定義:程序是正在執行的程式的例項(an instance of a computer program that is being executed),或者更加簡稱之為“執行中的程式”(但並非一個程

== equals 的恩怨情仇

這篇講明 == 與 equals 的區別 Java中資料型別分為基本資料型別和引用資料型別 基本資料型別不用通過new關鍵字來建立變數,直接儲存“值”並置於堆疊中,更加高效。 如:boolean、char、byte、short、int、long、float

MVVM的恩怨情仇

記得面試那會兒,因為有一點MVVM的使用經驗,跟面試官談了一下。我的觀點是,ViewModel封裝展示邏輯,不包含介面呼叫,介面呼叫封裝在另一個類裡面(比如xxx API),然後在controller呼叫API類拿到資料後由ViewModel封裝好給到檢視層。當

喬布斯比爾蓋茨的傳奇人生 兩位天才的恩怨情仇

  北京時間10月6日上午《紐約時報》網路版報道,蘋果宣佈公司聯合創始人、前CEO史蒂夫 喬布斯辭世,終年56歲。這位夢想家的黯然辭世,讓世人惋惜,他的影響力已經遠遠超出了PC行業,iPhone、iPad等產品可以說改變了人們的生活方式。我們在敬仰這位偉人的同時,更應該學習他的創新精神。   作為美國兩

jqjs的恩怨情仇

var is_selected = new Array(); var obj = $('.is_selected'); obj.each(function(e,v){ if(v.checked){

【asp.net core 系列】2 控制器路由的恩怨情仇

0. 前言 在上一篇文章中,我們初步介紹了asp.net core,以及如何建立一個mvc專案。從這一篇開始,我將為大家展示asp.net core 的各種內容,並且嘗試帶領大家來挖掘其中的內在邏輯。 當然,那是以後的事情。這一篇將通過自定義一個控制器來為大家介紹asp.net core mvc 中控制器和路

[拾 得]pipe和xargs的恩怨情仇

命令參數 字母 得到 實現 朋友 -i org 標準輸入 echo                 Photo by Joshua Sortino on Unsplash 堅持知識分享,該文章由Alopex編著, 轉載請註明源地址: http://www.cnblo

Linux磁盤管理(blockinode)

分享圖片 磁盤 軟鏈接文件 更多 硬盤分區 sta 文件恢復 size 內容 1 硬盤block與inode詳解 1.1 Sector(扇區)與Block(塊) 1) 硬盤的最小存儲單位:sector(扇區),每個扇區儲存512字節;操作系統會一次性連續讀取多個扇區,

Objective-C Block函數指針比較

其他 可執行文件 調試 objective 運行 obj 子類 函數指針 延長 相似點 1.函數指針和Block都可以實現回調的操作,聲明上也很相似,實現上都可以看成是一個代碼片段。 2.函數指針類型和Block類型都可以作為變量和函數參數的類型。(typedef定義別名

託管堆堆疊

記憶體格局通常分為四個區   全域性資料區:存放全域性變數,靜態資料,常量   程式碼區:存放所有的程式程式碼   棧區:存放為執行而分配的區域性變數,引數,返回資料,返回地址等,   堆區:即自由儲存區

桌子堆疊上下文

桌子與堆疊上下文   或許有人會問,桌子與堆疊上下文有什麼關係?我想說一句很欠揍的話,它們沒什麼關係。   那我為什麼要取個這樣的標題呢?因為你們都認識桌子,卻不一定能認出來堆疊上下文。但是我如果問你什麼是桌子,你怎麼說?它並沒有一個明確的定義,但是你看到一個東西,就可以知道它是不是

開發-測試-產品直接的恩怨情仇

大家平常調侃開發,又去寫bug了,雖然是一句玩笑話,但是世界上真的存在沒有bug的程式嗎,不知道,最近看到一個段子寫的特別的好,一天一個程式設計師在加班加點的寫東西,然後佛看到了,對程式設計師說,看你很辛苦,天天加班加點的寫東西,我可以滿足你一個願望,然後程式設計師就許願了,說,希望在我有生

再談方法呼叫堆疊

再談方法呼叫與堆和棧 在JVM裡面,最重要的兩個執行時資料區,無非就是堆和棧了。 關於堆 堆記憶體是被多個執行緒共享的,而棧記憶體是執行緒私有的。堆主要用來儲存執行時所有的物件資料和各種陣列,簡單點說通過new建立的例項,都會在堆上分配空間。堆在虛擬機器啟動時建立,並且堆具有自動垃圾回收

深入理解hashmap(三)雜湊表和二叉搜尋樹的恩怨情仇

前面兩篇文章介紹了hashmap的原始碼和理論,今天把剩餘的部分紅黑樹講一下。理解好紅黑樹,對我們後續對hashmap或者其他資料結構的理解都是很有好處的。比方說為什麼後面jdk要把hashmap中的單鏈表更新成紅黑樹? 要理解紅黑樹首先要弄清楚普通二叉樹的一些基本概念 父節點和子節點,這個我就不多說了。

java之引數傳遞堆疊-隨筆一

之前看到一個問題:java的引數傳遞到底是值傳遞還是引用傳遞呢? 首先,我們來看看java的堆(heap)和棧(stack)吧! 堆是jvm虛擬機器所管理的記憶體中最大的一塊,主要用來儲存new的物件例項或陣列(當然會有一些別的東西,比如類變數)。java堆是被所有執行緒所共享的一塊記憶體,在java虛擬

display:inline-blockfloat:left的區別

display與float是我們常用的佈局方式。像display:inline-block;與float:left是我們將元素水平排列的方式。像水平導航欄就可以用這兩種方式去實現。那這兩種實現方式有什麼區別呢? 1.display: inline-block;會產生留白,需要將父元素的f

引入TSS堆疊切換

【0】README text description from orange’s implemention of a os and for complete code ,please visit https://github.com/pac

程式設計師和專案經理之間的恩怨情仇

我本來是一個程式猿,我轉行做產品經理是為了"報復 "社會,因為我曾經被傷害過…… 段子1 程式設計師和專案經理上了火車…… 一個年輕的程式設計師和一個專案經理登上了一列在山裡行駛的火車,他們發現列車上幾乎都坐滿了,只有兩個在一起的空位,這個空位的對面是一個老奶奶和一個年輕漂亮的姑娘,兩人上前坐了