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

原文地址https://www.jishudog.com/8744/html

推薦??:

推薦作者:iOS的火影亂斗

地址

內(nèi)存布局


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

不同內(nèi)存布局區(qū)域的含義
stack(棧):方法調(diào)用
heap(堆):通過alloc等分配的對象
bss:未初始化的全局變量
data:已初始化的全局變量
text:程序代碼

內(nèi)存管理方案

  • taggedPointer
  • NONPointer_ISA
  • 散列表(很復(fù)雜的數(shù)據(jù)結(jié)構(gòu)输莺,引用計數(shù)表故黑、弱引用表)
散列表
  • SideTables()(非嵌入式系統(tǒng)中包含64個SideTable)苏揣,實際是一個哈希表涉枫,通過對象的指針找到對應(yīng)的引用計數(shù)表或弱引用表,在哪一個SideTable中
  • SideTable結(jié)構(gòu)
    包含自旋鎖 引用計數(shù)表 弱引用表
  • 為什么不是一個SideTable?
    存在效率問題,如果多個對象在對同一張表進行引用計數(shù)時块仆,就會等待前一個對象操作結(jié)束才能操作。引用分離鎖的方案王暗,可以提高效率
  • 如果實現(xiàn)快速分流悔据?(哈希查找的過程)
    根據(jù)對象的地址,通過一個均勻散列函數(shù)的計算就可以得到數(shù)組下標索引值

散列表中數(shù)據(jù)結(jié)構(gòu)

  • 自旋鎖(Spinlock_t
    是一種忙等的鎖(當前鎖已被其他線程獲取俗壹,就會不斷的探測這個鎖是否被釋放)
    適用于輕量訪問
  • 引用計數(shù)表(RefcountMap
    ptr ——> DisguisedPtr(obj) ——>size_t
    提高查找效率科汗,插入和獲取都是通過同一個哈希算法,避免了數(shù)組遍歷
  • 弱引用表(weal_table_t
    ptr ——> Hash函數(shù)——>value

ARC&&MRC

  1. MRC 手動引用計數(shù)
    • alloc
    • retain
    • release
    • retainCount
    • autorelease
    • dealloc

2.ARC 自動引用計數(shù)

  • ARC是LLVM和Runtime協(xié)作的結(jié)果
  • ARC禁止手動調(diào)用retain策肝、release肛捍、retainCount、dealloc
  • ARC中新增weak之众、strong屬性關(guān)鍵字

引用計數(shù)

  • alloc
    經(jīng)過一系列調(diào)用拙毫,最終調(diào)用的C函數(shù)malloc,此時并沒有設(shè)置引用計數(shù)為1(但是通過retainCount得知是1棺禾,在后面會講到)

  • retain
    經(jīng)過兩次Hash查找缀蹄,找到對應(yīng)的引用計數(shù)值,然后進行+1的操作

  • release
    經(jīng)過兩次Hash查找,找到對應(yīng)的引用計數(shù)值缺前,然后進行-1的操作

  • retainCount
    經(jīng)過兩次Hash查找蛀醉,找到對應(yīng)的引用計數(shù)值,然后與1相加(因此剛alloc的對象衅码,在對應(yīng)的引用計數(shù)表中實際是沒有這個映射的)

  • dealloc
    這里有一個iOS交流圈:891 488 181 不管你是大牛還是小白都歡迎入駐 拯刁,分享BAT,阿里面試題、面試經(jīng)驗逝段,討論技術(shù)垛玻, 大家一起交流學(xué)習(xí)成長!

    判斷時候可以釋放的條件(五個條件缺一不可)

    • 沒有使用nonpointer_isa
    • 沒有weak指針指向
    • 沒有有關(guān)聯(lián)對象
    • 沒有使用ARC或者涉及C++
    • 當前對象的引用計數(shù)沒有通過SideTable中的引用計數(shù)表來存儲的

[圖片上傳失敗...(image-584a89-1608785619322)]

object_dospose()函數(shù)內(nèi)部實現(xiàn)分析


clearDeallocating()內(nèi)部實現(xiàn)

弱引用


weak變量的添加過程

如何添加weak變量的?
對象指針在經(jīng)過編譯器的編譯之后調(diào)用objc_initweak()奶躯,然后storeweak()方法帚桩,經(jīng)過一系列的函數(shù)調(diào)用,最終在weak_register_no_lock()進行弱引用變量的添加嘹黔,通過hash算法位置查找账嚎,如果已經(jīng)存在當前對象對應(yīng)的弱引用數(shù)組,則直接加進去儡蔓,如果沒有則創(chuàng)建新個新的弱引用數(shù)組郭蕉,存放新的weak指針


系統(tǒng)如何實現(xiàn)將廢棄的weak指針置為nil

系統(tǒng)如何實現(xiàn)將廢棄的weak指針置為nil?
當對象被dealloc后廢棄之后,會調(diào)用弱引用清除的相關(guān)函數(shù)浙值。然后在函數(shù)實現(xiàn)中恳不,根據(jù)當前對象指針,查找弱引用表开呐,把當前對象對應(yīng)的弱引用都拿出來,然后遍歷所有的弱引用指針置為nil

自動釋放池

AutoreleasePool的實現(xiàn)原理是怎么樣的规求?

AutoreleasePool是以棧為結(jié)點筐付,通過雙向鏈表的形式組合而成的數(shù)據(jù)結(jié)構(gòu)。編譯器會將@autoreleasepool{}改寫阻肿,如下 圖瓦戚。實際objc_autoreleasePoolPop函數(shù)在內(nèi)部做了pop操作,批量將autoreleasepool中的所有的對象都會做一次release操作


編譯器改寫@autoreleasepool{}

下面對上面的主要函數(shù)進行一個簡單的說明

AutoreleasePool的結(jié)構(gòu)
  • 是以棧為結(jié)點通過雙向鏈表的形式組合而成
  • 是和線程一一對應(yīng)的

什么是雙向鏈表丛塌?


雙向 鏈表結(jié)構(gòu)

[obj autorelease]的實現(xiàn)(對象加入自動釋放池)

先判斷當前next指針是否指向棧頂较解,如果不是直接加入;如果是赴邻,則增加一個棧結(jié)點到鏈表上印衔,在新的棧添加對象;移動next指針

AutoreleasePoolPage::push實現(xiàn)流程(釋放池多層嵌套)
  • 插入哨兵對象

AutoreleasePoolPage::pop實現(xiàn)流程(與push相反)
  • 根據(jù)傳入的哨兵對象找到對應(yīng)的位置
  • 給上次push操作之后添加的對象依次添加release消息
  • 回退next指針到正確的位置
AutoreleasePool為何可以嵌套使用姥敛?

多次插入哨兵對象奸焙,也就是對一個新的releasePool的創(chuàng)建,如果當前棧沒有滿,則不需要創(chuàng)建新的page,如果滿了与帆,新增一個棧節(jié)點

下面這個圖中了赌,array對象在什么時候釋放呢?

答:在檔次runloop將要結(jié)束的時候調(diào)用AutoreleasePoolPage:pop(),對array對象執(zhí)行release操作

AutoreleasePool的使用場景玄糟?

在for循環(huán)中勿她,alloc圖片數(shù)據(jù)等內(nèi)存消耗較大的場景手動插入autoreleasePool,每一次for循環(huán)都進行一次內(nèi)存的釋放阵翎,降低內(nèi)存消耗

循環(huán)引用

  • 自循環(huán)引用
  • 相互循環(huán)引用
  • 多循環(huán)引用

自循環(huán)引用 對自身強持有



相互循環(huán)引用



多循環(huán)引用
常見的循環(huán)引用以及破除方法:
  • 代理(delegate)
  • block
  • NSTimer
  • 大環(huán)引用
如何破除循環(huán)引用嫂拴?
  • 避免產(chǎn)生循環(huán)引用
  • 在合適的時機手動斷環(huán)
具體解決方案有哪些?
  • __weak
  • __block
  • __unsafe_unretained(與weak等效)
__block在ARC和MRC條件下的區(qū)別
  • MRC下贮喧,__block修飾對象不會增加其引用計數(shù)筒狠,避免了循環(huán)引用
  • ARC下,__block修飾對象會被強引用箱沦,無法避免辩恼,需手動破環(huán)
__unsafe_unretained破解
  • 修飾對象不會增加其引用計數(shù),避免了循環(huán)引用
  • 如果找修飾對象在某一事跡被釋放谓形,產(chǎn)生懸空指針
循環(huán)引用的示例灶伊?(平時開發(fā)時是否有遇到循環(huán)引用,又是怎么解決的寒跳?)
  1. Block使用示例(在后面block講解時)
  2. NSTimerd的循環(huán)引用問題

文章到這里就結(jié)束了聘萨,你也可以私信我及時獲取面試資料。如果你有什么意見和建議歡迎給我留言童太。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末菇夸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子硼身,更是在濱河造成了極大的恐慌幻赚,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爆惧,死亡現(xiàn)場離奇詭異狸页,居然都是意外死亡,警方通過查閱死者的電腦和手機扯再,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門芍耘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人熄阻,你說我怎么就攤上這事斋竞。” “怎么了饺律?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵窃页,是天一觀的道長跺株。 經(jīng)常有香客問我,道長脖卖,這世上最難降的妖魔是什么乒省? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮畦木,結(jié)果婚禮上袖扛,老公的妹妹穿的比我還像新娘。我一直安慰自己十籍,他們只是感情好蛆封,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著勾栗,像睡著了一般惨篱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上围俘,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天砸讳,我揣著相機與錄音,去河邊找鬼界牡。 笑死簿寂,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的宿亡。 我是一名探鬼主播常遂,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼挽荠!你這毒婦竟也來了克胳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤坤按,失蹤者是張志新(化名)和其女友劉穎毯欣,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體臭脓,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年腹忽,在試婚紗的時候發(fā)現(xiàn)自己被綠了来累。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡窘奏,死狀恐怖嘹锁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情着裹,我是刑警寧澤领猾,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響摔竿,放射性物質(zhì)發(fā)生泄漏面粮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一继低、第九天 我趴在偏房一處隱蔽的房頂上張望熬苍。 院中可真熱鬧,春花似錦袁翁、人聲如沸柴底。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柄驻。三九已至,卻和暖如春焙压,著一層夾襖步出監(jiān)牢的瞬間鸿脓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工冗恨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留答憔,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓掀抹,卻偏偏與公主長得像虐拓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子傲武,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348