iOS內(nèi)存管理面試題

內(nèi)存管理面試題

  • 使用CADisplayLink、NSTimer有什么注意點?

  • 介紹下內(nèi)存的幾大區(qū)域

  • 講一下你對 iOS 內(nèi)存管理的理解

  • ARC 都幫我們做了什么?

  • LLVM + Runtime

  • weak指針的實現(xiàn)原理

  • autorelease對象在什么時機會被調(diào)用release

  • 方法里有局部對象, 出了方法后會立即釋放嗎

CADisplayLink、NSTimer使用注意

image-20220305223013784

GCD定時器

  • NSTimer依賴于RunLoop,如果RunLoop的任務過于繁重,可能會導致NSTimer不準時

  • 而GCD的定時器會更加準時

image-20220305223206417

iOS程序的內(nèi)存布局

  • 保留

  • 代碼段:編譯之后的代碼

  • 數(shù)據(jù)段

    字符串常量:比如NSString *str = @"123"

    已初始化數(shù)據(jù):已初始化的全局變量、靜態(tài)變量等

    未初始化數(shù)據(jù):未初始化的全局變量、靜態(tài)變量等

  • 棧:函數(shù)調(diào)用開銷,比如局部變量。分配的內(nèi)存空間地址越來越小

  • 堆:通過alloc、malloc、calloc等動態(tài)分配的空間,分配的內(nèi)存空間地址越來越大

  • 內(nèi)核區(qū)

Tagged Pointer

  • 從64bit開始,iOS引入了Tagged Pointer技術,用于優(yōu)化NSNumber、NSDate、NSString等小對象的存儲

  • 在沒有使用Tagged Pointer之前, NSNumber等對象需要動態(tài)分配內(nèi)存、維護引用計數(shù)等,NSNumber指針存儲的是堆中NSNumber對象的地址值

  • 使用Tagged Pointer之后,NSNumber指針里面存儲的數(shù)據(jù)變成了:Tag + Data,也就是將數(shù)據(jù)直接存儲在了指針中

  • 當指針不夠存儲數(shù)據(jù)時,才會使用動態(tài)分配內(nèi)存的方式來存儲數(shù)據(jù)

  • objc_msgSend能識別Tagged Pointer,比如NSNumber的intValue方法,直接從指針提取數(shù)據(jù),節(jié)省了以前的調(diào)用開銷

  • 如何判斷一個指針是否為Tagged Pointer?

    iOS平臺,最高有效位是1(第64bit)

    Mac平臺,最低有效位是1

OC對象的內(nèi)存管理

  • 在iOS中,使用引用計數(shù)來管理OC對象的內(nèi)存

  • 一個新創(chuàng)建的OC對象引用計數(shù)默認是1,當引用計數(shù)減為0,OC對象就會銷毀,釋放其占用的內(nèi)存空間

  • 調(diào)用retain會讓OC對象的引用計數(shù)+1,調(diào)用release會讓OC對象的引用計數(shù)-1

  • 內(nèi)存管理的經(jīng)驗總結(jié)

    當調(diào)用alloc、new、copy、mutableCopy方法返回了一個對象,在不需要這個對象時,要調(diào)用release或者autorelease來釋放它

    想擁有某個對象,就讓它的引用計數(shù)+1;不想再擁有某個對象,就讓它的引用計數(shù)-1

  • 可以通過以下私有函數(shù)來查看自動釋放池的情況\

    extern void _objc_autoreleasePoolPrint(void);

引用計數(shù)的存儲

image-20220305223518247

Dealloc

當一個對象要釋放時,會自動調(diào)用dealloc,接下的調(diào)用軌跡是

  • dealloc
  • _objc_rootDealloc
  • rootDealloc
  • object_dispose
  • objc_destructInstance、free
image-20220305223619352

**

自動釋放池

  • 自動釋放池的主要底層數(shù)據(jù)結(jié)構(gòu)是:__AtAutoreleasePool、AutoreleasePoolPage

  • 調(diào)用了autorelease的對象最終都是通過AutoreleasePoolPage對象來管理的

  • 源碼分析

    clang重寫@autoreleasepool

    objc4源碼:NSObject.mm

image-20220305223721181

AutoreleasePoolPage的結(jié)構(gòu)

  • 每個AutoreleasePoolPage對象占用4096字節(jié)內(nèi)存,除了用來存放它內(nèi)部的成員變量,剩下的空間用來存放autorelease對象的地址
  • 所有的AutoreleasePoolPage對象通過雙向鏈表的形式連接在一起
  • 調(diào)用push方法會將一個POOL_BOUNDARY入棧,并且返回其存放的內(nèi)存地址
  • 調(diào)用pop方法時傳入一個POOL_BOUNDARY的內(nèi)存地址,會從最后一個入棧的對象開始發(fā)送release消息,直到遇到這個POOL_BOUNDARY
  • id *next指向了下一個能存放autorelease對象地址的區(qū)域

Runloop和Autorelease

iOS在主線程的Runloop中注冊了2個Observer

  • 第1個Observer監(jiān)聽了kCFRunLoopEntry事件,會調(diào)用objc_autoreleasePoolPush()

  • 第2個Observer

    監(jiān)聽了kCFRunLoopBeforeWaiting事件,會調(diào)用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()

    監(jiān)聽了kCFRunLoopBeforeExit事件,會調(diào)用objc_autoreleasePoolPop()

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容