系统底层源码分析(12)——alloc如何开辟内存空间

2021-06-12  本文已影响0人  无悔zero

上一篇:系统底层源码分析(11)——alloc、init、new
下一篇:系统底层源码分析(13)——alloc如何关联类

接着上一篇继续看,上一篇提到calloc,但是calloc得要在另一份源码中查看。

  1. libmalloc源码继续探究:
void *
calloc(size_t num_items, size_t size)
{
    void *retval;
    retval = malloc_zone_calloc(default_zone, num_items, size);
    if (retval == NULL) {
        errno = ENOMEM;
    }
    return retval;
}
void *
malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)
{
    ...
    ptr = zone->calloc(zone, num_items, size);//控制台打印函数地址,可以得到default_zone_calloc
    ...
    return ptr;
}
  1. 来到zone->calloc,如果继续点进去就会进入循环。此时我们应该调用calloc函数,运行打印一下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);////控制台打印函数地址,可以得到nano_calloc
}
  1. 然后这里的zone->calloc也一样打印:
nano_calloc
static void *
nano_calloc(nanozone_t *nanozone, size_t num_items, size_t size)
{
    ...
    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);
}
static void *
_nano_malloc_check_clear(nanozone_t *nanozone, size_t size, boolean_t cleared_requested)
{
    MALLOC_TRACE(TRACE_nano_malloc, (uintptr_t)nanozone, size, cleared_requested, 0);

    void *ptr;
    size_t slot_key;
    size_t slot_bytes = segregated_size_to_fit(nanozone, size, &slot_key); // Note slot_key is set here
    mag_index_t mag_index = nano_mag_index(nanozone);

    nano_meta_admin_t pMeta = &(nanozone->meta_data[mag_index][slot_key]);

    ptr = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next));
    ...
    return ptr;
}
  1. 最后我们来到_nano_malloc_check_clear,代码很长,我们最需要看关于内存大小的地方:
#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;
    
    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;
}

最终开辟的内存空间大小由于字节对齐,可能和申请的不一样。

1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第
个数据成员放在offset0的地方,以后每个数据成员存储的起始位置要
从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,
结构体等)的整数倍开始(比如int4字节,则要从4的整数倍地址开始存储。

2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从
其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b
里有char,int, double等元素,那b应该从8的整数倍开始存储。)

3:收尾工作:结构体的总大小,也就是sizeof的结果, 必须是其内部最大
成员的整数倍,不足的要补齐。

举个例子:

这里的内部最大元素是double,所以内存大小为8的整数倍:

  1. Person1age字节大小为4,由于字节对齐,加4补全为8
    Person1height字节大小为8,不用补。
    Person1name字节大小为1,由于字节对齐,加7补全为8
    所以Person1总内存大小为24

  2. Person2age字节大小为4,而后面紧接着name,不足8,先不补。
    Person2name字节大小为1,前面紧接着age,所以加3,一起补全为8
    Person2height字节大小为8,不用补。
    所以Person1总内存大小为16

图解
上一篇下一篇

猜你喜欢

热点阅读