內存管理

一、內存佈局

  • stack:方法調用
  • heap:經過alloc等分配內存
  • bss:未初始化的全局變量等
  • data:已初始化的全局變量等
  • text:程序代碼

二、內存管理方案

  • TaggedPointer
  • NONPOINTER_ISA
  • 散列表
散列表

三、數據結構

  • Spinlock_t "忙等"鎖,輕量訪問
  • RefcountMap
    size_t
  • weak_table_t

四、MRC / ARC

  • MRC alloc/retain/release/retainCount/autorelease/dealloc
  • ARC LLVM和Runtime協做; ARC中禁止手動調用retain/release/retainCount/dealloc; 新增strong/weak屬性關鍵字

五、引用計數

  1. alloc,最終調用calloc,此時引用計數爲0
  2. retain實現
SideTable& table = SideTables()[this];
size_t& refcntStorage = table.refcnts[this];
refcntStorage += SIDE_TABLE_RC_ONE;
複製代碼
  1. release實現
SideTable& table = SideTables()[this];
RefcountMap::iterator it = table.refcnts.find(this);
it->second -= SIDE_TABLE_RC_ONE;
複製代碼
  1. retainCount實現
SideTable& table = SideTables()[this];
size_t refcnt_result = 1;
RefcountMap::iterator it = table.refcnts.find(this);
refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;
複製代碼

5.dealloc 數據結構

object_dispose()
objc_destructInstance()

clearDeallocating()

6. 弱引用

{
    id __weak obj1 = obj;
}

{
    id obj1;
    objc_initWeak(&obj1, obj);
}
複製代碼

七、自動釋放池

void *ctx = objc_autoreleasePoolPush();
...
objc_autoreleasePoolPop(ctx);
複製代碼
void *objc_autoreleasePoolPush(void) <=> void *AutoreleasePoolPage::push(void)

void objc_autoreleasePoolPop(void* ctx) <=> AutoreleasePoolPage::pop(void* ctx)
複製代碼
  • 以棧爲結點經過雙向鏈表的形式組合而成
  • 和線程一一對應

  • RunLoop將要結束時調用AutoreleasePoolPage::pop()
  • 多層嵌套就是屢次插入哨兵對象
  • for循環中含有內存消耗較大的場景時,如圖片對象的建立,手動插入AutoreleasePool

八、循環引用

分類
  • 自循環引用
  • 相互循環引用
  • 多循環引用
存在的場景
  • 代理
  • Block
  • NSTimer
  • 大環引用
解決方案
  • __weak
  • __block: MRC下,__block修飾的對象不回增長引用計數,避免循環引用; ARC下,__block修飾的對象會被強引用,沒法避免循環引用,須要手動解環
  • __unsafe_unretained:修飾對象不會增長引用計數,避免循環引用;可是被修飾對象被釋放時,會產生懸垂指針
NSTimer循環引用問題

相關文章
相關標籤/搜索