在iOS-底層原理 02:alloc & init & new 源碼分析文章中,alloc
有3個核心操作,其中一個就是calloc
,即申請內(nèi)存,這就是今天需要探索的內(nèi)容,其實(shí)探索的本質(zhì)也是為了驗(yàn)證 ios中對象中實(shí)際的對齊方式是8字節(jié)對齊
objc4中分析calloc 源碼
- 首先從alloc進(jìn)入objc的源碼,找到
obj = (id)calloc(1, size);
操作,涉及的方法順序是alloc --> _objc_rootAlloc --> callAlloc --> _objc_rootAllocWithZone --> _class_createInstanceFromZone
這里calloc的探索需要切換到 libmalloc
源碼中,可以在這里下載最新版,接著往下走
libmalloc中分析calloc源碼
- 在可編譯的libmalloc中定義一個可編譯的target,在main中使用
calloc
創(chuàng)建一個指針
- 進(jìn)入calloc的源碼實(shí)現(xiàn),其中的關(guān)鍵代碼在于
1713行的 malloc_zone_calloc
- 其中
default_zone
是一個默認(rèn)的zone,目的就是引導(dǎo)程序進(jìn)入一個創(chuàng)建真正zone
的流程
- 其中
-
進(jìn)入
malloc_zone_calloc
的源碼實(shí)現(xiàn),關(guān)鍵代碼是1441行的zone->calloc
- 其中
zone->calloc
傳入的zone 就是 上一步中的default_zone
- 這個關(guān)鍵代碼的
目的
就是申請一個指針,并將指針地址返回
- 其中
-
在進(jìn)入
zone->alloc
的源碼,發(fā)現(xiàn)是一個calloc
的聲明,到此,源碼就無法繼續(xù)跟進(jìn)了
那么重點(diǎn)來了!!!想要繼續(xù)跟進(jìn)源碼,可以通過以下方式:
在
malloc_zone_calloc
中的關(guān)鍵代碼,即ptr = zone->calloc(zone, num_items, size);
處,加一個斷點(diǎn),然后運(yùn)行-
斷點(diǎn)斷在 ptr位置,想要進(jìn)入zone->calloc源碼實(shí)現(xiàn),有兩種方式:
按住
control
+step into
,進(jìn)入calloc
的源碼實(shí)現(xiàn)-
,然后通過lldb命令
p zone->callocde
查找源碼實(shí)現(xiàn),通過打印得知zone->calloc
的源碼實(shí)現(xiàn)在default_zone_calloc
方法,然后全局搜索default_zone_calloc
方法,找到具體實(shí)現(xiàn)
- 進(jìn)入calloc的源碼實(shí)現(xiàn),其中主要由兩部分操作
- 創(chuàng)建真正的
zone
,即runtime_default_zone
方法 - 使用真正的
zone
進(jìn)行calloc
- 創(chuàng)建真正的
斷點(diǎn)斷在zone的位置,此時通過lldb命令p zone->alloc
是不行的,因?yàn)?code>zone還沒有賦值
zone 未賦值的驗(yàn)證
-
進(jìn)入
runtime_default_zone
的源碼實(shí)現(xiàn)
-
進(jìn)入
inline_malloc_default_zone
的源碼實(shí)現(xiàn),通過查看malloc_zones
的值發(fā)現(xiàn)是NULL
,可以得出,此時的zone還未賦值
繼續(xù)跟蹤源碼
- 回到
default_zone_calloc
方法,繼續(xù)執(zhí)行,斷在zone->calloc
部分,此時同樣可以通過上述的兩種方法任選其一進(jìn)入 calloc的源碼實(shí)現(xiàn)nano_calloc
- 進(jìn)入
nano_calloc
方法,其中的關(guān)鍵代碼是 878,此時的p是pointer表示指針
和前面的 ptr一樣,主要由兩部分邏輯- 如果要開辟的空間小于
NANO_MAX_SIZE
,則進(jìn)行則進(jìn)行nanozone_t
的malloc
- 反之,就進(jìn)行
helper_zone
流程
- 如果要開辟的空間小于
- 進(jìn)入
_nano_malloc_check_clear
源碼,將if else 折疊,看主流程- 其中
segregated_next_block
就是指針內(nèi)存開辟算法,目的是找到合適的內(nèi)存并返回 -
slot_bytes
是加密算法的鹽
(其目的是為了讓加密算法更加安全,本質(zhì)就是一串自定義的數(shù)字)
- 其中
- 進(jìn)入
segregated_size_to_fit
加密算法源碼, 通過算法邏輯,可以看出,其本質(zhì)就會16字節(jié)對齊算法
#define SHIFT_NANO_QUANTUM 4
#define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM) // 16
static MALLOC_INLINE size_t
segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)
{
size_t k, slot_bytes;
//k + 15 >> 4 << 4 --- 右移 + 左移 -- 后4位抹零,類似于16的倍數(shù),跟 k/16 * 16一樣
//---16字節(jié)對齊算法,小于16就成0了
if (0 == size) {
size = NANO_REGIME_QUANTA_SIZE; // Historical behavior
}
k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta
slot_bytes = k << SHIFT_NANO_QUANTUM; // multiply by power of two quanta size
*pKey = k - 1; // Zero-based!
return slot_bytes;
}
在iOS-底層原理 05:內(nèi)存對齊原理文末,已經(jīng)提及過該算法,這里不再過多說明
- 回到
_nano_malloc_check_clear
方法,進(jìn)入segregated_next_block
源碼,這個方法主要就是獲取內(nèi)存指針
- 但是如果是第一次走到
segregated_next_block
函數(shù),band不存在,緩存也不會存在,所以會調(diào)用segregated_band_grow
,來開辟新的band
- 但是如果是第一次走到
- 進(jìn)入
segregated_band_grow
源碼,主要是開辟新的band
先記錄libmalloc源碼中malloc分析的思路,需要時間研究源碼,后續(xù)再補(bǔ)充完善!!!