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