iOS之malloc分析
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
malloc
函数是alloc
的核心方法之一,负责开辟内存空间
项目中,只能找到malloc_size
的方法定义,它的代码实现在libmalloc
源码中
探索libmalloc
源码
进入calloc
函数
void *
calloc(size_t num_items, size_t size) {
return _malloc_zone_calloc(default_zone, num_items, size, MZ_POSIX);
}
进入_malloc_zone_calloc
函数
源码中只能找到calloc
的函数声明,但是无法进入
void *(* MALLOC_ZONE_FN_PTR(calloc))(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */
在项目中,搜索calloc
关键字,没有找到任何线索
这种情况,可以尝试打印zone->calloc
- 找到函数的真身:default_zone_calloc
在全局搜索calloc
时,虽然找不到函数实现,但是找到了calloc
赋值代码。有赋值必然会存储值,通过打印也许可以得到线索
或者,尝试Always Show Disassembly
查看汇编代码
- 也可得到相同线索:default_zone_calloc
来到default_zone_calloc
函数
static void *
default_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size) {
zone = runtime_default_zone();
return zone->calloc(zone, num_items, size);
}
又遇到了zone->calloc
函数,继续使用lldb
打印
来到nano_malloc
函数
进入_nano_malloc_check_clear
函数
- segregated_size_to_fit
:计算内存大小
- segregated_next_block
:开辟内存空间
进入segregated_size_to_fit
函数,计算出16字节
内存对齐后的大小
``` static MALLOC_INLINE size_t segregated_size_to_fit(nanozone_t nanozone, size_t size, size_t pKey) { size_t k, slot_bytes;
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;
}
``
NANO_REGIME_QUANTA_SIZE和
SHIFT_NANO_QUANTUM`定义:
```
define SHIFT_NANO_QUANTUM 4
define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM) // 16
``
-
1左移
4位,即:
16进入
segregated_next_block`函数,开辟内存空间
- 堆区开辟的空间是不连续的,期间可能因多线程、小于最大限制地址等原因,需要重新尝试while
。当开辟空间成功,返回指针地址
内存对齐算法
在segregated_size_to_fit
函数中,内存对齐的算法为
(size + 15) >> 4 << 4
算法作用为
16字节
对齐,保证分配的内存大小,必须是16
的整数倍,与算法(x + N) & ~N
有异曲同工之妙。\ 假设:传入的size
为40
\size + 15 = 55
,0011 0111
\ 右移4位
,0000 0110
\ 左移4位
,0011 0000
\ 转换10
进制为48
结构体内部,成员变量以8字节
对齐。但是在堆区分配对象的内存大小,以16字节
对齐
系统为什么要这样设计?
假设,堆区分配对象的内存大小,也按照8字节
对齐。读取时,遇到多个连续存储的8字节
对象,容易出现野指针或内存越界访问
再有,NSObject
自身占8字节
,自定义对象一般来说也会有自定义的成员变量,所以自定义对象的大小,在大部分情况下,不会小于16字节
所以,在堆区分配对象的内存大小,16字节
对齐为最好的选择
malloc
流程图