iOS calloc

2021-08-06  本文已影响0人  唱歌的鼻涕泡
calloc

浅究 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;
}
上一篇 下一篇

猜你喜欢

热点阅读