iOS備戰(zhàn)之內(nèi)存管理(二)

內(nèi)存管理方案

iOS操作系統(tǒng)是怎么管理內(nèi)存的摄闸,本次就來(lái)詳細(xì)的分析不同情況下使用的不同方案懂诗。

簡(jiǎn)要的說(shuō)有三種內(nèi)存管理方案在不同情況下使用。對(duì)于一些小對(duì)象墨叛,采用的是TaggedPointer內(nèi)存管理方案;對(duì)于64位架構(gòu)的應(yīng)用程序模蜡,采用的是NONPOINTER_ISA內(nèi)存管理方案漠趁;剩下的就是我們常說(shuō)的引用計(jì)數(shù)表和弱引用表內(nèi)存管理方案。

在開始之前忍疾,我們需要知道一些基本的知識(shí):字節(jié)是內(nèi)存的基本單位闯传,32位系統(tǒng)中一個(gè)指針占用4個(gè)字節(jié);64位系統(tǒng)中一個(gè)指針占用8個(gè)字節(jié)卤妒。沒(méi)有內(nèi)存優(yōu)化的情況下甥绿,從32位系統(tǒng)到64位系統(tǒng)后字币,邏輯沒(méi)有變化,但是對(duì)象占用的內(nèi)存會(huì)翻倍共缕。

1洗出、TaggedPointer

在64位處理器后,Apple提出的內(nèi)存管理方案图谷。引入TaggedPointer之后翩活,相同邏輯能減少一半的內(nèi)存占用,以及3倍的訪問(wèn)速度提升便贵,100倍的創(chuàng)建菠镇、銷毀提升。存取性能很高嫉沽!

TaggedPointer主要是用來(lái)處理小對(duì)象辟犀,比如NSNumber、NSDate等這一類占用內(nèi)存比較小的對(duì)象绸硕,它們往往不需要8個(gè)字節(jié)堂竟,這個(gè)時(shí)候可以把一個(gè)對(duì)象的指針拆成兩部分,一部分保存數(shù)據(jù)玻佩,另一部分作為特殊標(biāo)記出嘹,表示這是一個(gè)特殊的指針,不指向任何地址咬崔。

如果存儲(chǔ)的數(shù)據(jù)大小超過(guò)TaggedPointer對(duì)象可存儲(chǔ)大小的時(shí)候税稼,系統(tǒng)將不會(huì)以TaggedPointer的方式進(jìn)行存儲(chǔ),將采用普通對(duì)象的方式進(jìn)行存儲(chǔ)垮斯。

最后總結(jié)一下:

  1. TaggedPointer的引入郎仆,給64位系統(tǒng)帶來(lái)了內(nèi)存的節(jié)省和運(yùn)行效率的提高,完美解決了小對(duì)象浪費(fèi)內(nèi)存的情況兜蠕。
  2. TaggedPointer通過(guò)在其最后一個(gè)bit位設(shè)置一個(gè)特殊標(biāo)記扰肌,用于將數(shù)據(jù)直接保存在指針本身中。
  3. TaggedPointer指針的值不是地址熊杨,是一個(gè)真正的值愤炸,不是真正的對(duì)象荡澎,所以內(nèi)存并不存儲(chǔ)在堆上枪狂,所以也不需要malloc和free碳想。
  4. TaggedPointer沒(méi)有isa指針,是一個(gè)特別的指針川陆,不指向任何一個(gè)地址剂习,所以我們?cè)谑褂脮r(shí)不能直接訪問(wèn)其isa對(duì)象。

參考:
https://blog.csdn.net/wangyanchang21/article/details/80570863
http://www.cocoachina.com/articles/13449
https://blog.csdn.net/Zsk_Zane/article/details/94492069
http://www.reibang.com/p/dcbf48a733f9

2、NONPOINTER_ISA

非指針型ISA內(nèi)存管理方案
arm64架構(gòu)下isa占用64bit位进倍,Apple為了優(yōu)化性能土至,提高內(nèi)存利用率购对,存儲(chǔ)類對(duì)象地址只用了33位猾昆,其他的bit位用來(lái)存儲(chǔ)一些內(nèi)存管理方案的數(shù)據(jù)。

objc源碼如下:

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

isa是一個(gè)結(jié)構(gòu)體骡苞,在isa的里面定義了一個(gè)位域:ISA_BITFIELD垂蜗,點(diǎn)擊查看這個(gè)宏:
(代碼分為兩部分,arm64和x86_64的不同結(jié)構(gòu))

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)
bit位 位數(shù) 表示的含義
nonpointer 1 0表示普通的isa解幽,1表示non pointer isa
has_assoc 1 是否有關(guān)聯(lián)對(duì)象贴见,0代表沒(méi)有,1代表有
has_cxx_dtor 1 當(dāng)前對(duì)象是否使用c++函數(shù)
shiftcls 33 當(dāng)前對(duì)象的類對(duì)象的指針地址
magic 6 等同0x2d躲株,調(diào)試器使用它來(lái)判斷對(duì)象是否完成了初始化
weakly_referenced 1 對(duì)象是否有弱引用指針
deallocating 1 對(duì)象是否正在dealloc
has_sidetable_rc 1 當(dāng)前isa指針中存儲(chǔ)的引用計(jì)數(shù)是否達(dá)到上限片部,達(dá)到上限后需要外掛一個(gè)sidetable來(lái)存儲(chǔ)引用計(jì)數(shù)
extra_rc 19 額外的引用計(jì)數(shù),當(dāng)前引用計(jì)數(shù)很小的時(shí)候霜定,存儲(chǔ)在此處

extra_rc存儲(chǔ)的引用計(jì)數(shù)档悠,實(shí)際引用計(jì)數(shù)應(yīng)該是extra_rc+1,比如extra_rc為6望浩,則真正的引用計(jì)數(shù)是7.
extra_rc占用了19的bit位辖所,可以存儲(chǔ)的最大引用計(jì)數(shù)是2^19 = 524288,超過(guò)它就需要外掛一個(gè)sidetable來(lái)存儲(chǔ)引用計(jì)數(shù)磨德,

在初始化isa源碼中缘回,
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
有一段代碼 :
newisa.shiftcls = (uintptr_t)cls >> 3;
從這里可以看到將類地址右移三位得到有效的33位 shiftcls 位。

https://mobile.51cto.com/hot-588313.htm

3典挑、散列表 SideTables()

此部分篇幅較長(zhǎng)酥宴,單獨(dú)解析。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末您觉,一起剝皮案震驚了整個(gè)濱河市拙寡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顾犹,老刑警劉巖倒庵,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異炫刷,居然都是意外死亡擎宝,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門浑玛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)绍申,“玉大人,你說(shuō)我怎么就攤上這事〖模” “怎么了胃碾?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)筋搏。 經(jīng)常有香客問(wèn)我仆百,道長(zhǎng),這世上最難降的妖魔是什么奔脐? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任俄周,我火速辦了婚禮,結(jié)果婚禮上髓迎,老公的妹妹穿的比我還像新娘峦朗。我一直安慰自己,他們只是感情好排龄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布波势。 她就那樣靜靜地躺著,像睡著了一般橄维。 火紅的嫁衣襯著肌膚如雪尺铣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天挣郭,我揣著相機(jī)與錄音迄埃,去河邊找鬼。 笑死兑障,一個(gè)胖子當(dāng)著我的面吹牛侄非,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播流译,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼逞怨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了福澡?” 一聲冷哼從身側(cè)響起叠赦,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎革砸,沒(méi)想到半個(gè)月后除秀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡算利,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年册踩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片效拭。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡暂吉,死狀恐怖胖秒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慕的,我是刑警寧澤阎肝,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站肮街,受9級(jí)特大地震影響风题,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜低散,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一俯邓、第九天 我趴在偏房一處隱蔽的房頂上張望骡楼。 院中可真熱鬧熔号,春花似錦、人聲如沸鸟整。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)篮条。三九已至弟头,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涉茧,已是汗流浹背赴恨。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伴栓,地道東北人伦连。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像钳垮,于是被迫代替她去往敵國(guó)和親惑淳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • iOS中內(nèi)存管理機(jī)制是開發(fā)中一項(xiàng)很重要的知識(shí)饺窿,了解iOS中內(nèi)存管理的規(guī)則不管是在開發(fā)中還是在學(xué)習(xí)中都能很大程度的幫...
    Horson19閱讀 1,205評(píng)論 0 4
  • iOS中內(nèi)存管理機(jī)制是開發(fā)中一項(xiàng)很重要的知識(shí)歧焦,了解iOS中內(nèi)存管理的規(guī)則不管是在開發(fā)中還是在學(xué)習(xí)中都能很大程度的幫...
    Horson19閱讀 1,936評(píng)論 0 7
  • iOS中內(nèi)存管理機(jī)制是開發(fā)中一項(xiàng)很重要的知識(shí),了解iOS中內(nèi)存管理的規(guī)則不管是在開發(fā)中還是在學(xué)習(xí)中都能很大程度的幫...
    Mr_Atom閱讀 3,410評(píng)論 1 4
  • 1肚医、內(nèi)存布局 stack:方法調(diào)用 heap:通過(guò)alloc等分配對(duì)象 bss:未初始化的全局變量等绢馍。 data:...
    AKyS佐毅閱讀 1,596評(píng)論 0 19
  • 目錄一、iOS的內(nèi)存管理方式? 1肠套、小對(duì)象的內(nèi)存管理 -- Tagged Pointer?? 1.1 Tagged...
    意一ineyee閱讀 2,649評(píng)論 3 38