iOS-內(nèi)存管理知識(shí)點(diǎn)整理

內(nèi)存管理.png

image.png

image.png

indexed標(biāo)識(shí)isa是否僅僅為一個(gè)內(nèi)存指針祭阀,如果為1的話就僅是一個(gè)內(nèi)存指針专控,如果為0的話則意味著內(nèi)存的64位不僅僅用于存儲(chǔ)內(nèi)存指針

has_assoc代表該對(duì)象是否有關(guān)聯(lián)屬性
has_cxx_dtor代表對(duì)象是否有和c++相關(guān)的屬性
shiftcls代表對(duì)象實(shí)際的內(nèi)存地址
weakly_referenced代表對(duì)象是否有弱引用指向
deallocating標(biāo)識(shí)對(duì)象是否正在被銷毀
has_sidetable_rc代表對(duì)象是否有額外的引用計(jì)數(shù)表
extra_rc代表對(duì)象的引用計(jì)數(shù)(當(dāng)對(duì)象的引用計(jì)數(shù)很小的時(shí)候?qū)ο蟮囊糜?jì)數(shù)就記錄在當(dāng)前對(duì)象的isa指針中)


image.png
image.png

為什么不是一個(gè)sidetable呢赢底?幸冻?
如果只有一個(gè)表的話系統(tǒng)的操作對(duì)象的引用計(jì)數(shù)時(shí)其他的對(duì)象就在等待辩越,這就降低了效率 黔攒。


image.png

使用64張table存儲(chǔ)的話就能實(shí)現(xiàn)并發(fā)操作不傅。

image.png

自旋鎖是循環(huán)訪問(wèn)的機(jī)制访娶,只適用于輕量訪問(wèn)的情況崖疤。

image.png

引用計(jì)數(shù)表的前兩位分別標(biāo)識(shí)該對(duì)象是否有弱引用以及是否處于正在銷毀狀態(tài)劫哼,所以計(jì)算引用計(jì)數(shù)時(shí)要向右偏移兩位

image.png

弱引用表是一張Hash表权烧,key為當(dāng)前對(duì)象的指針地址般码,vlaue為指向當(dāng)前對(duì)象的弱引用對(duì)象鏈表

MRC和ARC的區(qū)別

image.png
image.png

ARC的本質(zhì)是編譯器和Runtime協(xié)作的結(jié)果

image.png

引用計(jì)數(shù)的管理機(jī)制

image.png

alloc的時(shí)候并沒(méi)有將對(duì)象的引用計(jì)數(shù)設(shè)置為1,而是retain的初始值為1

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

    size_t refcnt_result = 1;
    
    table.lock();
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it != table.refcnts.end()) {
        // this is valid for SIDE_TABLE_RC_PINNED too
        refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;
    }
    table.unlock();
    return refcnt_result;
}

retainCount的實(shí)現(xiàn):先在sidetables表集合中根據(jù)對(duì)象的指針地址找到對(duì)應(yīng)的sidetable囊嘉,再sidetable中的通過(guò)hash查找找到對(duì)象對(duì)應(yīng)的引用計(jì)數(shù),如果當(dāng)前的表中對(duì)象是新建的話震檩,此時(shí)hash表中的it->second為0抛虏,返回默認(rèn)值累加值1.
如果不為0迂猴,則將對(duì)應(yīng)數(shù)值向右偏移兩位后加1.

image.png
id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
    assert(!isa.indexed);
#endif
    SideTable& table = SideTables()[this];

    if (table.trylock()) {
        size_t& refcntStorage = table.refcnts[this];
        if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
            refcntStorage += SIDE_TABLE_RC_ONE;
        }
        table.unlock();
        return (id)this;
    }
    return sidetable_retain_slow(table);
}

對(duì)象的調(diào)用dealloc后的銷毀過(guò)程

image.png

要判斷對(duì)象是否有isa指針,弱引用息尺,關(guān)聯(lián)對(duì)象搂誉,c++相關(guān)和引用計(jì)數(shù)表并對(duì)應(yīng)執(zhí)行銷毀操作炭懊。

image.png

object_dispose 實(shí)現(xiàn)

image.png

objc_destructInstance實(shí)現(xiàn)


image.png

銷毀c++和關(guān)聯(lián)對(duì)象后再銷毀對(duì)象的引用計(jì)數(shù)和弱引用

image.png

弱引用初始化時(shí)Runtime會(huì)調(diào)用obc_initWeak函數(shù)初始化一個(gè)新的weak指針指向?qū)ο螅?jīng)過(guò)objc_storeWeak調(diào)整參數(shù)凯旋,最終由weak_register_no_lock創(chuàng)建弱引用鏈表存儲(chǔ)對(duì)象的指針至非。


image.png

image.png

清除weak變量并設(shè)置nil的過(guò)程如下


image.png

釋放時(shí)谐鼎,調(diào)用sidetable_clearDeallocating函數(shù)狸棍,然后調(diào)用weak_clear_no_lock()根據(jù)對(duì)象的地址獲取到為weak表中的指向該對(duì)象的弱指針數(shù)組草戈,遍歷數(shù)組將數(shù)組中的所有項(xiàng)都設(shè)置為nil唐片,最后把entry從weak表中刪除涨颜。

總結(jié)一下 添加weak變量中會(huì)調(diào)用 initWeak()庭瑰,storeWeak()弹灭,weak_register_no_lock()函數(shù)穷吮。清除weak變量置nil會(huì)調(diào)用learDeallocating()酒来,weak_clear_no_lock()函數(shù)。在添加和刪除的過(guò)程中都不斷的使用hash查找定位變量在weak表中的位置辽社。

自動(dòng)釋放池autoreleasePool

問(wèn)題1.圖中的array是什么時(shí)候被釋放的滴铅?汉匙?
在每次runloop開(kāi)始都會(huì)調(diào)用一次autoreleasePoolPush操作噩翠,每次runloop結(jié)束的時(shí)候都會(huì)調(diào)用一次autoreleasePoolPop操作伤锚,array就是在pop操作的過(guò)程中被release釋放屯援。


image.png

問(wèn)題2.autoreleasePool的實(shí)現(xiàn)原理是什么狞洋?吉懊?
問(wèn)題3.autoreleasePool是如何實(shí)現(xiàn)嵌套使用的惕它?淹魄?
問(wèn)題4.在實(shí)際開(kāi)發(fā)過(guò)程中autoreleasePool的應(yīng)用場(chǎng)景是怎樣的堡距?羽戒?

image.png

在實(shí)際的開(kāi)發(fā)過(guò)程中@autoreleasePool{}會(huì)被改寫成下圖的代碼會(huì)在要執(zhí)行的代碼前后分別加上autoreleasePoolPush和autoreleasePoolPop

image.png
image.png
image.png

autoreleasePoolPage的本質(zhì)是以棧為節(jié)點(diǎn)通過(guò)雙向鏈表的形式組合而成結(jié)構(gòu)體,而且autoreleasePoolPage與具體的線程相關(guān)聯(lián)

image.png

autoreleasePoolPush操作是向autoreleasePoolPage棧中插入哨兵對(duì)象標(biāo)識(shí)本次的autorelease開(kāi)始存儲(chǔ)數(shù)據(jù)位置,autoreleasePoolPop首先找到相應(yīng)的autoreleasePoolPage并對(duì)棧進(jìn)行出棧操作企量,每出棧一個(gè)對(duì)象的同時(shí)會(huì)調(diào)用對(duì)象的release方法直到出棧至最上方的哨兵對(duì)象停止出棧届巩。

image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png

NSTimer產(chǎn)生循環(huán)引用的原因和解決方案

[NSTimer scheduledTimerWithTimeInterval:interval target:object selector:@selector(fire:) userInfo:userInfo repeats:repeats];

NSTimer注冊(cè)到當(dāng)前線程的runloop中后 當(dāng)前的runloop會(huì)持有timer的強(qiáng)引用方咆,同時(shí)timer強(qiáng)引用當(dāng)前對(duì)象形成環(huán)引用瓣赂。


image.png

解決方法:在timer和object中間添加中間對(duì)象煌集,中間對(duì)象分別弱引用timer和object苫纤,在每次執(zhí)行timer的方法時(shí)都判斷oject是否存在,存在則調(diào)用方法不存在則消除timer


image.png
#import "NSTimer+WeakTimer.h"

@interface TimerWeakObject : NSObject
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL selector;
@property (nonatomic, weak) NSTimer *timer;

- (void)fire:(NSTimer *)timer;
@end

@implementation TimerWeakObject

- (void)fire:(NSTimer *)timer
{
    if (self.target) {
        if ([self.target respondsToSelector:self.selector]) {
            [self.target performSelector:self.selector withObject:timer.userInfo];
        }
    }
    else{
        [self.timer invalidate];
    }
}

@end

@implementation NSTimer (WeakTimer)

+ (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)interval
                                         target:(id)aTarget
                                       selector:(SEL)aSelector
                                       userInfo:(id)userInfo
                                        repeats:(BOOL)repeats
{
    TimerWeakObject *object = [[TimerWeakObject alloc] init];
    object.target = aTarget;
    object.selector = aSelector;
    object.timer = [NSTimer scheduledTimerWithTimeInterval:interval target:object selector:@selector(fire:) userInfo:userInfo repeats:repeats];
    
    return object.timer;
}

@end
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末栗弟,一起剝皮案震驚了整個(gè)濱河市乍赫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惋增,老刑警劉巖诈皿,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纫塌,死亡現(xiàn)場(chǎng)離奇詭異措左,居然都是意外死亡避除,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門性宏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)毫胜,“玉大人酵使,你說(shuō)我怎么就攤上這事焙糟〈┐椋” “怎么了悦穿?”我有些...
    開(kāi)封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵栗柒,是天一觀的道長(zhǎng)傍衡。 經(jīng)常有香客問(wèn)我负蠕,道長(zhǎng)遮糖,這世上最難降的妖魔是什么欲账? 我笑而不...
    開(kāi)封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任赛不,我火速辦了婚禮踢故,結(jié)果婚禮上惹苗,老公的妹妹穿的比我還像新娘桩蓉。我一直安慰自己劳闹,他們只是感情好本涕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蔬胯。 她就那樣靜靜地躺著位他,像睡著了一般鹅髓。 火紅的嫁衣襯著肌膚如雪窿冯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音仰挣,去河邊找鬼膘壶。 笑死洲愤,一個(gè)胖子當(dāng)著我的面吹牛柬赐,可吹牛的內(nèi)容都是我干的肛宋。 我是一名探鬼主播万矾,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼薪丁!你這毒婦竟也來(lái)了馅精?” 一聲冷哼從身側(cè)響起洲敢,我...
    開(kāi)封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤压彭,失蹤者是張志新(化名)和其女友劉穎壮不,沒(méi)想到半個(gè)月后询一,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體健蕊,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缩功,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年掂之,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了世舰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跟压。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡震蒋,死狀恐怖查剖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情效扫,我是刑警寧澤菌仁,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布济丘,位于F島的核電站摹迷,受9級(jí)特大地震影響泪掀,放射性物質(zhì)發(fā)生泄漏颂碘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一头岔、第九天 我趴在偏房一處隱蔽的房頂上張望塔拳。 院中可真熱鬧,春花似錦峡竣、人聲如沸靠抑。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颂碧。三九已至,卻和暖如春载城,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背费就。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工诉瓦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓睬澡,卻偏偏與公主長(zhǎng)得像固额,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子煞聪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1斗躏、內(nèi)存布局 stack:方法調(diào)用 heap:通過(guò)alloc等分配對(duì)象 bss:未初始化的全局變量等。 data:...
    AKyS佐毅閱讀 1,600評(píng)論 0 19
  • 前言 從我開(kāi)始學(xué)習(xí)iOS的時(shí)候昔脯,身邊的朋友瑟捣、網(wǎng)上的博客都告訴我iOS的內(nèi)存管理是依靠引用計(jì)數(shù)的,然后說(shuō)引用計(jì)數(shù)大于...
    蓋世英雄_ix4n04閱讀 554評(píng)論 0 1
  • 文章目錄 一.內(nèi)存管理準(zhǔn)則 二.屬性內(nèi)存管理修飾符全解析 三.block中的weak和strong 四.weak是...
    YouKnowZrx閱讀 1,055評(píng)論 5 10
  • iOS中內(nèi)存管理機(jī)制是開(kāi)發(fā)中一項(xiàng)很重要的知識(shí)栅干,了解iOS中內(nèi)存管理的規(guī)則不管是在開(kāi)發(fā)中還是在學(xué)習(xí)中都能很大程度的幫...
    Horson19閱讀 1,941評(píng)論 0 7
  • 每日5000步√ 《捕捉兒童敏感期》放肆的語(yǔ)言 語(yǔ)言的發(fā)展是一個(gè)螺旋式的發(fā)展過(guò)程迈套,每一個(gè)時(shí)期對(duì)語(yǔ)言的敏感點(diǎn)有所不同...
    因蒙而萌閱讀 175評(píng)論 0 0