系统底层源码分析(12)——alloc如何开辟内存空间
2021-06-12 本文已影响0人
无悔zero
上一篇:系统底层源码分析(11)——alloc、init、new
下一篇:系统底层源码分析(13)——alloc如何关联类
接着上一篇继续看,上一篇提到calloc
,但是calloc
得要在另一份源码中查看。
- 从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;
}
- 来到
zone->calloc
,如果继续点进去就会进入循环。此时我们应该调用calloc
函数,运行打印一下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
}
- 然后这里的
zone->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;
}
- 最后我们来到
_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
))的数据成员,第
个数据成员放在offset
为0
的地方,以后每个数据成员存储的起始位置要
从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,
结构体等)的整数倍开始(比如int
为4
字节,则要从4
的整数倍地址开始存储。2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从
其内部最大元素大小的整数倍地址开始存储。(struct a
里存有struct b
,b
里有char
,int
,double
等元素,那b
应该从8
的整数倍开始存储。)3:收尾工作:结构体的总大小,也就是
sizeof
的结果, 必须是其内部最大
成员的整数倍,不足的要补齐。
举个例子:
这里的内部最大元素是double
,所以内存大小为8
的整数倍:
-
Person1
的age
字节大小为4
,由于字节对齐,加4
补全为8
。
Person1
的height
字节大小为8
,不用补。
Person1
的name
字节大小为1
,由于字节对齐,加7
补全为8
。
所以Person1
总内存大小为24
。 -
Person2
的age
字节大小为4
,而后面紧接着name
,不足8
,先不补。
Person2
的name
字节大小为1
,前面紧接着age
,所以加3
,一起补全为8
。
Person2
的height
字节大小为8
,不用补。
所以Person1
总内存大小为16
。