記憶體管理Release和Retain實現原理

落葉1052發表於2019-03-06

引入計數儲存在SideTables表中儲存結構如圖所示。

記憶體管理Release和Retain實現原理

1.Retain實現原理。

1.1對物件retain之後實現過程。

id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
   assert(!isa.nonpointer);
#endif
   SideTable& table = SideTables()[this];//從SideTables中取出SideTable。
   
   table.lock();
   size_t& refcntStorage = table.refcnts[this];//根據this地址取出refcntStorage
   if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {//如果沒有超出引用計數最大值
       refcntStorage += SIDE_TABLE_RC_ONE;//引用計數加4也就是向左移動兩位。
   }
   table.unlock();

   return (id)this;
}

複製程式碼

1.2引用計數值獲取。

objc_object::sidetable_retainCount()
{
  SideTable& table = SideTables()[this];

  size_t refcnt_result = 1;
  //物件初始化時預設為1之後每次對物件retain引入計數值加1
  table.lock();
  RefcountMap::iterator it = table.refcnts.find(this);//獲取RefcountMap
  if (it != table.refcnts.end()) {//能找到this物件
      // this is valid for SIDE_TABLE_RC_PINNED too
      refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;//
      //it->second是獲取到it的value
      //>> SIDE_TABLE_RC_SHIFT上邊獲取的value向左移動兩位獲取到引用計數器的值。
      
  }
  table.unlock();
  return refcnt_result;//返回引用計數值
}
複製程式碼

2.Release實現原理

objc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
#endif
    SideTable& table = SideTables()[this];//獲取到SideTable

    bool do_dealloc = false;//是否要被dealloc

    table.lock();//鎖住table表
    RefcountMap::iterator it = table.refcnts.find(this);//獲取到RefcountMap
    if (it == table.refcnts.end()) {//沒有找到this
        do_dealloc = true;
        table.refcnts[this] = SIDE_TABLE_DEALLOCATING;//設定為需要dealloc
    } else if (it->second < SIDE_TABLE_DEALLOCATING) {//沒有引用計數值
        // SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.
        do_dealloc = true;
        it->second |= SIDE_TABLE_DEALLOCATING;//給it->second賦值
    } else if (! (it->second & SIDE_TABLE_RC_PINNED)) {//引用計數減一
        it->second -= SIDE_TABLE_RC_ONE;
    }
    table.unlock();
    if (do_dealloc  &&  performDealloc) {//物件需要被銷燬
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);//傳送訊息呼叫dealloc銷燬物件。
    }
    return do_dealloc;
}
複製程式碼

2.1通過this沒有找到RefcountMap

如果沒找打RefcountMap物件do_dealloc 設定位 true table.refcnts[this] = SIDE_TABLE_DEALLOCATING設定標誌位為1為下邊清除weak——table——t表中的物件設定為nil做準備。 ##2.2引入計數已經清0

do_dealloc = true;
it->second |= SIDE_TABLE_DEALLOCATING;
複製程式碼

程式碼和2.1操作相同標誌位設定。

2.3引用計數減1。

it->second -= SIDE_TABLE_RC_ONE;
複製程式碼

2.4根據標誌位判斷是否需要dealloc。

if (do_dealloc  &&  performDealloc) {//物件需要被銷燬
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);//傳送訊息呼叫dealloc銷燬物件。
    }
複製程式碼

如果標誌位都為YES呼叫objc_msgSend銷燬物件。

3.refcntStorage結構事例

SIDE_TABLE_WEAKLY_REFERENCED (1UL<<0)

 SIDE_TABLE_WEAKLY_REFERENCED(是否有弱引用)1,有0,沒有
複製程式碼

SIDE_TABLE_DEALLOCATING (1UL<<1)

SIDE_TABLE_DEALLOCATING(是否要被銷燬)1,被標記 0,不需要被銷燬
複製程式碼

SIDE_TABLE_RC_ONE (1UL<<2)

SIDE_TABLE_RC_ONE新增引用計數的值左移兩位想當於加4.
複製程式碼

SIDE_TABLE_RC_PINNED (1UL<<(WORD_BITS-1))

SIDE_TABLE_RC_PINNE(如果為1引用計數到達最大值)
複製程式碼
#ifdef __LP64__
#   define WORD_SHIFT 3UL
#   define WORD_MASK 7UL
#   define WORD_BITS 64//64位系統定義為64
#else
#   define WORD_SHIFT 2UL
#   define WORD_MASK 3UL
#   define WORD_BITS 32
#endif
複製程式碼

記憶體管理Release和Retain實現原理

相關文章