全局塊, 棧塊及堆塊

        最近比較空, 剛好有些時間可以看看書, 總結一下之前的知識, 本人空閒的時候, 有一種深深的焦慮, 感覺總該學點什麼, 時代變化太快, 自己學的只是總結的也不是很充分, 一天天混了過去, 不如充實的過好美一天, 畢竟都是24小時, 由於最近很多直接寫在了印象筆記中, 好多都沒有寫在博客上, /(ㄒoㄒ)/~~還是不扯了, 趕緊總結我的.

定義塊的時候, 其所佔的內存區域是分配在棧中的. 也就是說, 塊只在定義它的那個範圍內有效. 例如, 如下的代碼可能就會很危險

void (^block)();

if(/* some condition */) {

   block = ^{

   NSLog(@"Block A");

   }

} else {

block = ^{

   NSLog(@"Block B");

   }

}

block();

      上面的兩個塊都分配在棧中. 編譯器會給每個塊分配棧內存,然而等離開了相應的範圍之後, 編譯器可能把分配給會的內存覆寫掉.於是, 這兩個塊只能保證在對應的if或者else語句範圍內有效. 這樣寫出來的代碼可以編譯, 但是運行起來時而正確,時而錯誤. 若編譯器未覆寫待執行的塊, 則程序照常運行, 若覆寫, 則程序崩潰.

    爲解決此問題, 可給對象發送copy消息以拷貝之,這樣的話, 就可以把塊從棧複製到堆上了,拷貝後的塊,可以在定義範圍之外使用. 而且, 一旦複製到堆上, 塊就成了帶引用計數的對象了, 後續的複製操作都不會真的執行復制,只是遞增塊對對象的引用計數.如果不再使用這個塊, 那就應該將其釋放, 在ARC環境下會自動釋放, 而手動管理引用計數時則需要自己來調用release方法,當引用計數降爲0後, 分配在堆上的塊, 會向其他對象一樣, 爲系統所回收. 而分配在棧上的塊, 則無需明確會像其他對象一樣, 爲系統所回收. 剛纔那段範例代碼有危險, 原因就是這樣的. 我們可以給代碼加上兩個copy方法調用, 就可以另其變得安全了;

除了堆塊和棧快之外, 還有一類塊叫做"全局塊".這種塊不捕捉任何狀態(比如外圍的變量等), 運行時也無需有狀態來參與. 塊所使用的整個內存區域, 在編譯期已經完全確定, 因此, 全局塊可以聲明在全局內存裏, 而不需要在每次用到的時候於棧中創建. 另外, 全局塊的拷貝操作是個空操作, 因爲全局塊絕不可能爲系統所回收, 這種塊實際上相當於單利. 下面就是個全局塊

void (^block)() = ^{

                        NSLog(@"This is a block");

                        };

由於運行該塊所需的全部信息都能在編譯期確定, 所以可把它做成全局塊. 這完全是中優化技術; 若把如此簡單的塊當成複雜的塊來處理, 那就會在複製以及丟棄該塊時執行一些無謂的操作.





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章