浅究 calloc
oc 代码中的 alloc 主要有三种作用 1、计算分配内存大小(字节对齐)2、向系统申请内存,并开辟 3、 绑定iSA指针
研究了 系统在没有优化的情况下的分配内存情况,那么现在研究一下 OC源码中是怎样向系统申请空间的
源码
1、一如即往的我们打开源码 走一走
id obj;
if (zone) {
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size);
}
不知不觉的又走到了巷子口,呸,关键口,我这边是一直都会走到
obj = (id)calloc(1, size);
那么我们去看看 calloc 到底做了什么!
calloc
void *
calloc(size_t num_items, size_t size)
{
return _malloc_zone_calloc(default_zone, num_items, size, MZ_POSIX);
}
给它两个入参,一个是开辟的个数,一个是开辟的大小,就是上面 字节对齐,优化后 的 内存开辟的大小
size = cls->instanceSize(extraBytes);
_malloc_zone_calloc
MALLOC_NOINLINE
static void *
_malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size,
malloc_zone_options_t mzo)
{
MALLOC_TRACE(TRACE_calloc | DBG_FUNC_START, (uintptr_t)zone, num_items, size, 0);
void *ptr;
if (malloc_check_start) {
internal_check();
}
ptr = zone->calloc(zone, num_items, size);
if (os_unlikely(malloc_logger)) {
malloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE | MALLOC_LOG_TYPE_CLEARED, (uintptr_t)zone,
(uintptr_t)(num_items * size), 0, (uintptr_t)ptr, 0);
}
MALLOC_TRACE(TRACE_calloc | DBG_FUNC_END, (uintptr_t)zone, num_items, size, (uintptr_t)ptr);
if (os_unlikely(ptr == NULL)) {
malloc_set_errno_fast(mzo, ENOMEM);
}
return ptr;
}
走到这一步,看的里面眼花缭乱了,分不清哪个是主线任务了,经验告诉我,许多判断语句里面是存放的标识位,那么我们着重看一看
ptr = zone->calloc(zone, num_items, size);
只有这个是对新 变量赋值的,不要怀疑了,我确实是预言家。
可是 不难发现,这又回去了,又是来到了一个 calloc
注释 p->a,其中p是指向一个结构体的指针,a是这个结构体类型的一个成员
不难看出zone 是一个指针 指向了 calloc(zone, num_items, size);
那么我们打印一下这个指针
打印指针
这算是一个小技巧吧,p 一下 生成的过程 ,结果惊喜的发现了 走的类名字
default_zone_calloc
那我走~~,走到这个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);
}
神奇的事情又发生了,它继续走到了
return zone->calloc(zone, num_items, size);
照葫芦画瓢,咱们再试试 p zone->calloc
nano_calloc
发现了新的线索
nano_calloc
static void *
nano_calloc(nanozone_t *nanozone, size_t num_items, size_t size)
{
size_t total_bytes;
if (calloc_get_size(num_items, size, 0, &total_bytes)) {
return NULL;
}
if (total_bytes <= NANO_MAX_SIZE) {
void *p = _nano_malloc_check_clear(nanozone, total_bytes, 1);
if (p) {
return p;
} else {
/* FALLTHROUGH to helper zone */
}
}
malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);
return zone->calloc(zone, 1, total_bytes);
}
哇 又来到了一个新世界,继续根据线索走
可以发现 第一行
if (calloc_get_size(num_items, size, 0, &total_bytes)) {
return NULL;
}
这是一个容错处理
malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);
下面这个是helper 一般带有help的 都不是主线任务,辅助要carry 太难了
void *p = _nano_malloc_check_clear(nanozone, total_bytes, 1);
排除了这么老半天终于察觉到了这行代码嫌疑最大,开整
_nano_malloc_check_clear
这里面开始 对 内存又进行了一步 16字节对齐
其中的核心代码是
ptr = segregated_next_block(nanozone, pMeta, slot_bytes, mag_index);
Note slot_key is set here 这里为哈希算法的盐
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;
}
网友评论