在上篇着重分析了
alloc的流程以及第一个核心点cls->instanceSize计算需要开辟的内存大小, 通过流程 知道_class_createInstanceFromZone这个方法里的三个核心点
现在分析下第二个关键代码objc = (id)calloc(1, size);这个源码在libmalloc,源码地址下载
NSObject *d = [NSObject alloc];
NSLog(@"%@ - %lu - %lu - %lu",d,sizeof(d),class_getInstanceSize([d class]),malloc_size((__bridge const void *)(d))); // 输出8 - 8 - 16
-
第一个输出的8是它的指针大小;
-
第二个是基于属性的8字节内存对齐(在上篇文章分析过,这里不赘述)
-
第三个的输出48字节, 我们可以通过苹果官方的
libmalloc-283.100.6工程来分析下上篇文章里第二个核心点obj = (**id**)calloc(1, size);做了那些事情;
打开libmalloc,开始接着分析malloc是怎么分配内存的?⛽️
上图是objc-781源码,通过对上边的调用嫁接到下边的另一份代码里.
- 来到
libmalloc源码, 继续调试探究; 跳到calloc代码里.
- 接着进入到
malloc_zone_calloc
void *
malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)
{
MALLOC_TRACE(TRACE_calloc | DBG_FUNC_START, (uintptr_t)zone, num_items, size, 0);
void *ptr;
if (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {
internal_check();
}
ptr = zone->calloc(zone, num_items, size);
if (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);
return ptr;
}
- 然后开始跳到
zone->calloc(zone,num_items,size),发现这里直接到不了方法实现;
点击ptr = zone->calloc(zone, num_items, size);只能看到如下的函数声明;
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 */
这个函数返回一个函数指针,相关知识点可以看文章底部 指针函数和函数指针的内容,所以通过控制台打印出它的指针内容;
点击ptr = zone->calloc(zone, num_items, size);只能看到如下的函数声明;
通过
LLDB调试找到zone->calloc(zone, num_items, size); 真正实现default_zone_calloc;
- 通过搜索来到
default_zone_calloc
断点走到return zone->clloc(zone, num_items, size); 让zone = runtime_default_zone执行完,(如果不执行这句,zone是没有值的,在LLDB调试找不到真正实现函数, 会无限递归).
和上一步也是一样的,通过LLDB调试找到真正实现的函数nano_calloc。
- 跳到
nano_calloc函数里
找到关键代码,即_nano_malloc_check_clear函数,
- 跳到
_nano_malloc_check_clear函数,对于盐的知识点可以看底部参考,
折叠非关键代码, 找到主线流程segregated_size_to_fit
- 跳到
segregated_size_to_fit函数里。
这里主要是对齐算法和上篇文章的位与对齐算法是一个道理;通过左移和右移,将低四位置为0, 进行16字节对齐。
内存对齐算法
到现在为止, 知道的16字节对齐的算法有俩种
alloc源码分析中的align16malloc源码分析中segregated_size_to_fit
字节对齐到底采用多少字节对齐?
通过这几篇文章写到有8字节对齐和16字节对齐,系统究竟采用哪种字节对齐?
- 通过之前对
class_getInstanceSize的分析,是8字节对齐,相对于一个对象来说,通过8字节分配的内存可以满足对象的需求。 - 但是
苹果粑粑为了防止各种错误,采取16字节对齐,保证容错的空间,内存中的各个对象彼此不是紧巴巴的挨着,对象之间显得宽松一些,虽然浪费一些空间,但苹果也会有各种优化手段,比如属性重拍等,并且也利于苹果以后的扩展。
拓展
加盐 Salt 参考 维基百科
简单来说加盐是一种提高散列内容的方式;具体可以看维基百科, 解释的很清楚呢;