美文网首页
01.OC实例对象的本质

01.OC实例对象的本质

作者: 白开了杯水 | 来源:发表于2021-08-18 18:20 被阅读0次

你知道NSObject实例对象占用了多少内存么?
要回答这道题,我们要探索下OC实例对象的本质,而实例对象的本质其实就是一个结构体,怎么证明呢?
首先创建一个工程,然后打开终端,cd到对应文件夹,然后执行以下命令:

xcrun -sdk iphoneos clang -arch arm64 -rewirte-objc OC源文件 -o 输入的cpp文件

可能你有疑惑,为什么要用终端命令?这里简单解释下,我们写的OC代码会转为C\C++代码,编译流程大概是这样子


编译流程

这里的命令其实就是做转换作用~
接下来我们继续用Xcode打开该cpp文件,然后查询NSObject,可以看到,会有一个NSObject_IMPL的结构体,其实这个就对应着NSObject类,如下图对比


NSObject类
转换后的NSObject结构体
那么我们想看NSObject对象占用了多少个内存,我们通过文件可以看到它只有一个Class类型的isa变量,它占用了8个字节,那是不是它只占用了8个字节的内存呢?答案其实不是的,是16个字节。如何证明?接下来我们用系统提供的方法来证明一下,来看一下代码
NSObject对象内存分配代码

运行起来可以看到分别输出了8和16,那究竟该信哪一个呢,煎蛋解释下这俩个方法的区别
class_geInstanceSize:它表达的是实例对象成员所需要用的内存
malloc_size:它表示系统实际分配给对象的内存
拿上面的例子举例,NSObject只有一个Class类型的isa成员变量,它占用8个字节,但由于系统会有一个内存对齐的规则,最少以16的倍数,所以会叠加到8到16个字节,哪怕后面的字节没有用到,NSObject内存如图


NSObject的内存布局
拓展1

如下图代码,打印结果是什么?


ani和dog继承内存代码

打印结果:16 16 24 32

你答对了吗?没答对没关系,让我来给你解释下,首先Animal多了一个int(4字节)的成员变量_age,加上了继承的NSObject的isa(8字节),总共就12字节,那为啥class_getInstanceSize获取的是16呢,因为class_getInstanceSize这个方法会采取内存对齐,通过源码我们可以看到它调用了alignedInstancedSIze函数,从该函数我们就知道它是带有对齐效果的函数了,所以对齐后是16,malloc系统分配不用说,肯定还是16,Dog新增了俩个int成员变量_no和_leg,这下子就有三个int和一个isa,那么就是12 + 8 = 20,至于为啥是24和32,还是内存对齐的操作,以8和16的倍数对齐 class_getInstanceSize源码
拓展2

方法占用了对象的内存吗?
答:不占用,要是占用的话,NSObject类那么多方法就不止8个字节了不是吗?它其实存在类的方法列表里面,为什么不存对象里面?因为方法对于多个对象来说都是同样的代码,不需要创建多份,但成员变量对于每个对象都有可能是不同的值,所以必须多份,后面会更详细介绍

拓展3

加一个属性的内存呢?
答:属性本质会生成一个成员变量和get set方法,所以同成员变量一致

其它:

苹果源码地址
查看内存地址之debug,打断点 -> 导航栏debug -> debug workflow - view memory 输入地址查看内存地址
LLDB一些指令

常用LLDB指令
本文参考自李明杰老师的教程

相关文章

网友评论

      本文标题:01.OC实例对象的本质

      本文链接:https://www.haomeiwen.com/subject/fjzgbltx.html