天天看点

iOS-底层原理 06:malloc 源码分析 思路

iOS 底层原理 文章汇总

在iOS-底层原理 02:alloc & init & new 源码分析文章中,

alloc

有3个核心操作,其中一个就是

calloc

,即申请内存,这就是今天需要探索的内容,其实探索的本质也是为了验证

ios中对象中实际的对齐方式是8字节对齐

objc4中分析calloc 源码

  • 首先从alloc进入objc的源码,找到

    obj = (id)calloc(1, size);

    操作,涉及的方法顺序是

    alloc --> _objc_rootAlloc --> callAlloc --> _objc_rootAllocWithZone --> _class_createInstanceFromZone

    iOS-底层原理 06:malloc 源码分析 思路

这里calloc的探索需要切换到

libmalloc

源码中,可以在这里下载最新版,接着往下走

libmalloc中分析calloc源码

  • 在可编译的libmalloc中定义一个可编译的target,在main中使用

    calloc

    创建一个指针
    iOS-底层原理 06:malloc 源码分析 思路
  • 进入calloc的源码实现,其中的关键代码在于

    1713行的 malloc_zone_calloc

    • 其中

      default_zone

      是一个默认的zone,目的就是引导程序进入一个创建真正

      zone

      的流程
      iOS-底层原理 06:malloc 源码分析 思路
  • 进入

    malloc_zone_calloc

    的源码实现,关键代码是1441行的

    zone->calloc

    iOS-底层原理 06:malloc 源码分析 思路
    • 其中

      zone->calloc

      传入的zone 就是 上一步中的

      default_zone

    • 这个关键代码的

      目的

      就是

      申请一个指针,并将指针地址返回

  • 在进入

    zone->alloc

    的源码,发现是一个

    calloc

    的声明,到此,源码就无法继续跟进了
    iOS-底层原理 06:malloc 源码分析 思路

那么重点来了!!!想要继续跟进源码,可以通过以下方式:

  • malloc_zone_calloc

    中的关键代码,即

    ptr = zone->calloc(zone, num_items, size);

    处,加一个断点,然后运行
  • 断点断在 ptr位置,想要进入zone->calloc源码实现,有两种方式:
    • 按住

      control

      +

      step into

      ,进入

      calloc

      的源码实现
    • ,然后通过lldb命令

      p zone->callocde

      查找源码实现,通过打印得知

      zone->calloc

      的源码实现在

      default_zone_calloc

      方法,然后全局搜索

      default_zone_calloc

      方法,找到具体实现
      iOS-底层原理 06:malloc 源码分析 思路
  • 进入calloc的源码实现,其中主要由两部分操作
    • 创建真正的

      zone

      ,即

      runtime_default_zone

      方法
    • 使用真正的

      zone

      进行

      calloc

      iOS-底层原理 06:malloc 源码分析 思路

断点断在zone的位置,此时通过lldb命令

p zone->alloc

是不行的,因为

zone

没有赋值

zone 未赋值的验证

  • 进入

    runtime_default_zone

    的源码实现
    iOS-底层原理 06:malloc 源码分析 思路
  • 进入

    inline_malloc_default_zone

    的源码实现,通过查看

    malloc_zones

    的值发现是

    NULL

    ,可以得出,此时的

    zone还未赋值

    iOS-底层原理 06:malloc 源码分析 思路

继续跟踪源码

  • 回到

    default_zone_calloc

    方法,继续执行,断在

    zone->calloc

    部分,此时同样可以通过上述的两种方法任选其一进入 calloc的源码实现

    nano_calloc

    iOS-底层原理 06:malloc 源码分析 思路
  • 进入

    nano_calloc

    方法,其中的关键代码是 878,此时的p是pointer表示

    指针

    和前面的 ptr一样,主要由两部分逻辑
    • 如果要开辟的空间小于

      NANO_MAX_SIZE

      ,则进行则进行

      nanozone_t

      malloc

    • 反之,就进行

      helper_zone

      流程
      iOS-底层原理 06:malloc 源码分析 思路
  • 进入

    _nano_malloc_check_clear

    源码,将if else 折叠,看主流程
    • 其中

      segregated_next_block

      就是指针内存开辟算法,目的是找到合适的内存并返回
    • slot_bytes

      是加密算法的

      (其目的是为了让加密算法更加安全,本质就是一串自定义的数字)
      iOS-底层原理 06:malloc 源码分析 思路
  • 进入

    segregated_size_to_fit

    加密算法源码, 通过算法逻辑,可以看出,其本质就会16字节对齐算法
#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;
    //k + 15 >> 4 << 4 --- 右移 + 左移 -- 后4位抹零,类似于16的倍数,跟 k/16 * 16一样
	//---16字节对齐算法,小于16就成0了
	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;
}
           

在iOS-底层原理 05:内存对齐原理文末,已经提及过该算法,这里不再过多说明

  • 回到

    _nano_malloc_check_clear

    方法,进入

    segregated_next_block

    源码,这个方法主要就是

    获取内存指针

    • 但是如果是第一次走到

      segregated_next_block

      函数,band不存在,缓存也不会存在,所以会调用

      segregated_band_grow

      ,来开辟新的

      band

      iOS-底层原理 06:malloc 源码分析 思路
  • 进入

    segregated_band_grow

    源码,主要是开辟新的band
    iOS-底层原理 06:malloc 源码分析 思路
先记录libmalloc源码中malloc分析的思路,需要时间研究源码,后续再补充完善!!!

参考链接

  • iOS 高级之美(六)—— malloc分析