底层学习-OC对象(上)

alloc底层流程

IMG_20160827_044605_HDR.jpg
黑暗不会永驻,黎明即将到来!

学习了oc这么多年,关于底层的东西也是很模糊,这个系列的文章将带大家一起发现探索关于oc的底层知识。正所谓万物皆对象,所以我们先从对象的创建开始吧!

alloc对象的指针地址和内存

  • 首先有一个疑问:对象是怎么创建的?由谁创建的?alloc? init?还是alloc init一起呢?上代码!!!
LGPerson *p1 = [LGPerson alloc];
LGPerson *p2 = [p1 init];
LGPerson *p3 = [p1 init];

// 打印之前也会有一些疑问:
// alloc 是不是有了内存 指针?
// init  内存是不是一样?

NSLog(@"%@-%p-%p",p1,p1,&p1);
NSLog(@"%@-%p-%p",p2,p2,&p2);
NSLog(@"%@-%p-%p",p3,p3,&p3);
    
// 输出打印:
<LGPerson: 0x600000fb4480>-0x600000fb4480-0x7ffeeac99180
<LGPerson: 0x600000fb4480>-0x600000fb4480-0x7ffeeac99178
<LGPerson: 0x600000fb4480>-0x600000fb4480-0x7ffeeac99170    
复制代码

我们可以发现p1,p2,p3的内存是指向的同一个地方,但是各自的指针地址却不一样,如下图。

WechatIMG499.png
由此得知,对象的创建是由alloc创建的,那它怎么做到的? init 有何用?接下来让我们继续探索。

底层探索的三种方法

  1. 符号断点:

image.png
打上断点后运行程序(以模拟器为例),control + step into

image.png

点住往下走
image.png
创建断点
image.png
继续过掉当前断点
image.png
走到libobjc.A.dylib动态库的objc_alloc方法

  1. 汇编 跟流程 – 符号断点

image.png
image.png
同符号断点一样操作

3.通过已知符号断点确定位置

image.png

image.png

汇编结合源码调试分析

定位objc源码
苹果开源源码地址:
opensource.apple.com
opensource.apple.com/tarballs/

image.png

image.png
可以下载底层源码进行跟踪调试分析代码,下载好的源码可能会编译不过去,报各种错,大家可以去看这篇文章 juejin.cn/post/684490… 来解决源码配置的问题。

编译器优化

在工程对应Target的Build Settings中,找到optimization level这一项
image.png
debug模式一般选None fast可以优化编译器编译速度,减少汇编代码

alloc的主线流程

跟踪源码,探查alloc底层实现

image.png

image.png

image.png

image.png

image.png
核心方法一:计算需开辟内存的大小
image.png

image.png

image.png
十六字节对齐
image.png
核心方法二:开辟内存 返回内存地址指针
image.png
核心方法三:指针与类绑定
image.png

image.png

image.png
到此alloc完成

字节对齐

  • 对象的内存大小由什么决定?–>成员变量

  • isa为啥是8字节?–>继承于NSObject

字节对齐原理

(x + WORD_MASK) & ~WORD_MASK

例如:
(8 + 7)& ~7 --> 15 & ~7  8字节对齐 取8的整数倍
 (8 + 7) >> 3 << 3
二进制显示
15:0000 1111
7: 0000 0111
~7:1111 1000
15 & ~7:0000 1000 = 8
复制代码
  • 为什么是8的倍数,而不是16或者32甚至更大呢?

首先如果内存不一样大,寄存器读取不断变化,会导致读取的速度变慢

都以8字节读取会变快,以空间换取时间

在各种数据类型里,最大的为8字节
image.png

对象的内存空间

image.png
0x011d800100008491:Isa

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享