Block的詳細介紹

關於block的介紹


==ios中的內存空間分級==ios

  1. 棧區
    • 存放函數參數值、局部變量、函數返回地址等,函數跳轉跳轉時現場保護(寄存器),這些系統都會幫咱們自動實現,無需咱們干預。 因此大量的局部變量,深遞歸,函數循環調用均可能耗盡棧內存而形成程序崩潰 。咱們每次調用函數,都會執行壓棧操做(在XCode的左側面板會看到一堆的函數調用棧)。
    • 特色是存取效率高,存取結構連續,可是空間很小,有系統自行分配以及管理棧的地址空間。
    • 一種先進後出,壓棧出棧更像是一個容器。
  2. 堆區
    • 平時涉及到內存管理基本上出自於這個區域。由malloc、alloc、copy(深複製)、new等方法觸發的效果就是在堆區進行內存分配。
    • 堆是存放在二級緩存中,生命週期由虛擬機的垃圾回收算法來決定(並非一旦成爲孤兒對象就能被回收)。因此調用這些對象的速度要相對來得低一些。
    • 數據呈現通常是樹狀的,相似鏈表式
  3. 常量區
    • 存放常量,由系統釋放以及分配。
  4. 靜態區
    • 該區域其實細分爲數據區以及BSS區(BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態內存分配。BSS節不包含任何數據,只是簡單的維護開始和結束的地址,以便內存區能在運行時被有效地清零。BSS節在應用程序的二進制映象文件中並不存在。)。數據區存放已經初始化好的靜態變量以及全局變量,而BSS區則存放尚未初始化好的靜態變量以及全局變量,由系統負責釋放以及分配。
    • 是存放開闢過和未開闢過靜態變量和全局變量的地方。
  5. 文本區
    • 放置已經編譯成二進制機器語言的代碼文本。會依照應用的運行狀況而依次調用。相似遊戲規則。

==block的分級==算法

  1. 全局區的Block__NSGlobalBlock__
    • 當咱們聲明一個block時,若是這個block沒有捕獲外部的變量,那麼這個block就位於全局區,此時對NSGlobalBlockretain、copy、release操做都無效。
  2. 棧區的Block__NSStackBlock__
    • 平時編程的時候不多遇到位於棧區的block,爲何呢?由於在ARC環境下,當咱們聲明而且定義了一個block,而且沒有爲Block添加額外的修飾符(默認是__strong修飾符),若是該Block捕獲了外部的變量,實質上是有一個從__NSStackBlock__轉變到__NSMallocBlock__的過程,只不過是系統幫咱們完成了copy操做,將棧區的block遷移到堆區,延長了Block的生命週期。對於棧區block而言,棧block在當函數退出的時候,該空間就會被回收。何時在ARC的環境下出現__NSStackBlock__呢?若是咱們在聲明一個block的時候,使用了__weak或者__unsafe__unretained的修飾符,那麼系統就不會爲咱們作copy的操做,不會將其遷移到堆區。
  3. 堆區的Block__NSMallocBlock__
    • 咱們須要手動調用copy方法才能夠將block遷移到堆區,而在ARC環境下,__strong修飾的(默認)block只要捕獲了外部變量就會位於堆區,NSMallocBlock支持retain、release,會對其引用計數+1或 -1。編程

      ==__block修飾符==緩存

  4. 應該是考慮到了block的特殊性,block也屬於「函數」的範疇,變量進入block,實際就是已經改變了做用域。在幾個做用域之間進行切換時,若是不加上這樣的限制,變量的可維護性將大大下降。又好比我想在block內聲明瞭一個與外部同名的變量,此時是容許呢仍是不容許呢?只有加上了這樣的限制,這樣的情景才能實現。因而棧區變成了紅燈區,堆區變成了綠燈區。
  5. 對於捕獲的普通的外部變量,block並不能做出修改。咱們要改變外部變量的內存地址,也就是使用__block修飾符將外部變量在棧中指針的內存地址,遷移到堆區中來。
  6. __block修飾符的根本操做就是改變外部變量的內存地址,並非簡單地使得寫操做生效。
  7. 那麼什麼狀況下不須要__block做爲修飾符。將block捕獲的外部變量使用static修飾或者將外部變量聲明爲全局變量,那麼block是能夠直接修改該外部變量的,由於全局變量或靜態變量在內存中的地址是固定的(存放於靜態區),Block在讀取該變量值的時候是直接從其所在內存讀出,獲取到的是最新值,而不是在定義時copy的常量。
  8. 某些圖方便直接用copy修飾生命block。直接拿到一個堆區block。裏面捕獲變量的過程當中就不須要修飾符來讓OS幫忙拷貝直接可使用了。可是原理必定要清晰,一個失控的機制遠比可控的機制恐怖的多。這裏須要警醒。多線程

    ==循環引用的原理==閉包

  9. 循環引用是由於出現了資源的持有閉環。OS的斷定機制會認爲這個空間仍在使用,因此相關聯的三方資源一個都不會釋放;
  10. __weak的弱引用替換掉__strong的時候會打破閉環釋放三方資源。可是隨之到來的是unsafe。這是須要注意的地方;函數

==block到底是個什麼東西==線程

  • 由上面種種,咱們能夠推測出。block算是一個另類的函數。是將代碼段閉包抽象爲一種對象調用的手段。

==多線程下的block==指針

  1. 存不存在資源搶奪?會出現哪些問題?若是有該怎麼避免?
相關文章
相關標籤/搜索