iOS底层原理:OC对象底层探索之开辟内存(二)

简介: 简介: 在上篇文章iOS底层原理(二):OC对象底层探索之alloc初探 中,我们体验了 objc 底层源码的调试流程,也介绍了一部分 [JQPerson alloc] 在底层的工作流程,最终在callAlloc中走到了_objc_rootAllocWithZone方法。那么今天我们就来继续探索_objc_rootAllocWithZone方法之后的流程吧!
内存优化

看完了结构体的内存对齐,我们再来看一下OC对象的内存对齐又是怎样的呢?


image.png

JQPerson中自定义的变量和JQStruct2的成员的类型和顺序是一模模一样样的,他们打印出来的内存大小都是24字节,也是一模模一样样的,乍一看,没毛病呀。大哥,你忘记了对象本身自带了一个变量isa指针吗?它也占了8个字节呢。所以这样一看,JQPerson中自定义的变量只占了16个字节,这就很奇怪了啊,变量的类型和顺序都是一样的啊。这到底是为啥呢?这就是接下来我们要说的内存优化。

来,我们具体看看是它是怎么优化的,上代码:


image.png


通过lldb断点打印可以看出 :

  1. isa的值通过读取 0x0000000109dc6658 (8字节)这个内存的数据;
  2. a的值通过读取 0x4067200000000000 (8字节)这个内存的数据;
  3. b的值通过读取 0x00000012 (4字节)这个内存的数据,
  4. c的值通过读取 0x0002 (2字节)这个内存的数据,
  5. d的值通过读取 0x0063 (2字节)(内存对齐,高位补0,所以这里看着就是俩字节了)这个内存的数据,

我们发现 int b,short c,char d,共用了一个8字节内存空间,系统进行了内存优化,将对象的属性或者变量存储顺序进行了重排,达到内存占用最小。

上面这个例子理解起来可能还不够透彻,下面我们在JQPerson中在增加一些属性,打印一下内存数据,一看就明白了。


image.png

image.png

看图👆,没有文字了!!!

由此我们可以得出结论:

  • OC对象与对象之间是以16字节对齐的。
  • 对象内部的成员变量之间是以8字节对齐的(OC最大数据类型是8字节,而每个对象都自带了一个8字节的isa)。
calloc 开辟内存

上面我们讲到了instanceSize方法计算对象所需的内存大小,并且拓展了内存对齐内存优化。接着,我们就来看一下calloc是怎么去开辟内存的。

好,我们断点快速来到_class_createInstanceFromZone方法中


image.png


这里可以看出,此时的obj还没有进行赋值,就已经有地址了,说明系统给obj分配了一块内存地址(脏地址)。


image.png


接着走断点,看到:执行calloc后打印的是一个16进制的指针地址,说明已经开辟了内存,但是和平常见到的地址指针(下图👇)不一样。


image.png


也就是说,calloc只是开辟了内存;但是这块内存空间并没有和相应的类进行关联。

我们一步一步来看,先点击calloc,进去看看calloc都做了什么?


image.png


发现这里进不去了,calloc没有提供方法实现,好想进去啊,怎么办?

拿出我们上篇文章讲的三种底层调试方法,符号断点跟一下流程


image.png


看到这里calloc方法在libsystem_malloc.dylib中,这是个系统库啊。毫不犹豫,直接去 Open Source 下载libsystem_malloc.dylib的源码啊。(ps:其实上面已经指出了calloc的位置,macOS 11.3/usr/include/malloc,天哪,这明显是个系统库啊)

好,接下里,我们拿malloc的源码编译调试,看看calloc的做了啥。上代码


image.png

  • 进入 calloc


image.png

  • 进入 _malloc_zone_calloc

image.png

33.png

  • 进入 zone->calloc,发现点不进去,怎么办呢?首先想到的是汇编跟一下流程。但是注意,C语言指针->指向的就是函数的首地址,我们直接打印一下zone->calloc看看


image.png

  • 看到下一个跳转是default_zone_calloc,全局搜索 default_zone_calloc

image.png

卧槽,又来一个zone->calloc

  • 断点来到这里,继续打印一下zone->calloc看看


image.png

  • 看到下一个跳转是nano_calloc,全局搜索 nano_calloc


image.png

  • 断点发现会执行到_nano_malloc_check_clear,进入_nano_malloc_check_clear看一下


image.png

  • 继续进入segregated_size_to_fit看看


image.png

这里发现只有201、202这两句核心代码:

k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta
slot_bytes = k << SHIFT_NANO_QUANTUM;

这两句啥意思呢?我们看到 >><<这两个符号,这很熟悉了啊,这不就是右移和左移嘛!

我们分别点击宏NANO_REGIME_QUANTA_SIZESHIFT_NANO_QUANTUM进去看一下都代表什么


image.png

知道了宏的定义,我们就还原一下上面201、202那两句代码:

k = (size + (1 << 4) - 1) >> 4; 
slot_bytes = k << 4;


这就很清晰了,前面内存对齐时我们讲过, >> 4 再 << 4 得出的结果就是16的整数倍,(size + (1 << 4) - 1) = size + 15。意思就是先给size升到16(二进制10000)以上,不足的位全抹0。这就是16进制对齐的算法!

我们拿上面传的40计算一下:


image.png

OK,到此,我们calloc的底层就结束了。

下面继续完善一下alloc的流程图:

image.png


总结


  • 结构体是以其最大成员的字节数对齐的。
  • 对象内部的成员变量之间是以8字节对齐的。
  • OC对象与对象之间是以16字节对齐的。
  • instanceSize 是计算实例对象所需要的内存大小
  • calloc 是系统为对象开辟内存

下一篇,我们来介绍OC对象的最后一个内容:isa关联类。敬请期待~



相关文章
|
2月前
|
算法 JavaScript 前端开发
新生代和老生代内存划分的原理是什么?
【10月更文挑战第29天】新生代和老生代内存划分是JavaScript引擎为了更高效地管理内存、提高垃圾回收效率而采用的一种重要策略,它充分考虑了不同类型对象的生命周期和内存使用特点,通过不同的垃圾回收算法和晋升机制,实现了对内存的有效管理和优化。
|
3月前
|
C++
【C++】深入解析C/C++内存管理:new与delete的使用及原理(二)
【C++】深入解析C/C++内存管理:new与delete的使用及原理
|
3月前
|
编译器 C++ 开发者
【C++】深入解析C/C++内存管理:new与delete的使用及原理(三)
【C++】深入解析C/C++内存管理:new与delete的使用及原理
|
3月前
|
存储 C语言 C++
【C++】深入解析C/C++内存管理:new与delete的使用及原理(一)
【C++】深入解析C/C++内存管理:new与delete的使用及原理
106 2
|
5月前
|
监控 算法 Java
Java内存管理:垃圾收集器的工作原理与调优实践
在Java的世界里,内存管理是一块神秘的领域。它像是一位默默无闻的守护者,确保程序顺畅运行而不被无用对象所困扰。本文将带你一探究竟,了解垃圾收集器如何在后台无声地工作,以及如何通过调优来提升系统性能。让我们一起走进Java内存管理的迷宫,寻找提高应用性能的秘诀。
|
4月前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
5月前
|
缓存 Java 编译器
Go 中的内存布局和分配原理
Go 中的内存布局和分配原理
|
8天前
|
iOS开发 开发者
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
|
2月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。