內(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é)一下:
- TaggedPointer的引入郎仆,給64位系統(tǒng)帶來(lái)了內(nèi)存的節(jié)省和運(yùn)行效率的提高,完美解決了小對(duì)象浪費(fèi)內(nèi)存的情況兜蠕。
- TaggedPointer通過(guò)在其最后一個(gè)bit位設(shè)置一個(gè)特殊標(biāo)記扰肌,用于將數(shù)據(jù)直接保存在指針本身中。
- TaggedPointer指針的值不是地址熊杨,是一個(gè)真正的值愤炸,不是真正的對(duì)象荡澎,所以內(nèi)存并不存儲(chǔ)在堆上枪狂,所以也不需要malloc和free碳想。
- 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ú)解析。