1. NSObject 对象占几个字节?
结论:
系统分配16字节给NSObject对象(malloc_size),但是对象内部只使用8个字节空间(64bit情况下。class_getIstance)
验证:
我们讨论NSObject对象占用内存的时候,其实是在考虑
NSObject *obj = [[NSObject alloc] init];
这里alloc开辟的内存空间,obj是指向这块开辟的空间的地址的指针。
如果想知道确定开辟的空间大小,我们需要了解alloc这块代码的源码,所以我们需要读取源码的 objc4文件。
源码地址:https://opensource.apple.com/tarballs/
由于源码都是C/C++写的,所以我们需要将OC文件 转换为C++文件,然后按照对应转换的内容进行查看对比。
那OC-->C++如何转换呢?
提供两种转换,由于xcode的编译是通过clang进行的,咱们通过clang进行抓换。
clang -rewite-objc main.m -o main.cpp
xcrun -sdk iphoneos clang -arm arm64 -rewite-objc main.m -o main.cpp
xcrun 在xcode上运行的
iphoneos 指的iphone系统
-arm 手机系统架构
arm64 手机系统架构64位
-rewite-objc main.m 对main.m文件转换
-o main.cpp 输出转换为c++形式的main文件
我们通过读取源码发现alloc-->allocWithZoom-->rootallocWithZoom-->class_createInstanc 代码最后发现如果开辟对象内存小于16字节,则给返回最小16字节。
xxxx_IMPL通常有这个,就是某个类的实现。
验证逻辑2:
我们通过查看内存数据进行验证,我们断点查看obj的地址,然后设置xcode的 debug-->debug workflow --> view mmemory。 然后我们找到obj指针指向的地址,查看里面内存情况,前8位就是被分配指向的地址,后8位是0。(16位进制中 1个16的进制位代表4个2进制位,也就是说2个16进制位代表8个2进制位也就是 1个字节)。
lldb使用命令
我们可以通过xcode自带的lldb工具对内存区间进行读取,写入的操作。
print 或者 p 打印的是对象所以信息
print object 或者 po 打印的是对象
memory read x10000000200x 读取这个地址
读取地址也可简写为 x + 地址
如果我们对读取出来内存格式,样子有要求,可以按照如下方式更改
x/ 3xg 地址
此处 3表示的读取出3串,可以改为4、5、6等其他数字
第二个x表示的16进制。d表示10进制、f表示浮点。
g:giant word 表示8字节。b:byte表示1字节、h:half word 表示2字节、w:word 表示4字节。
memory write x11000101022 9
将地址处改写成数字9
2、OC对象本质是什么?
OC对象本质是结构体。
person 对象的实现,我们可以通过搜索 struct person_IMPL 进行查看。我们需要记住在OC中,如果查看一个对象的实现我们需要找到对应的xxxx_IMPL的实现即可。IMPL也就是单词implementation 实现的缩写。
这里需要导入一张图,展示相关结构体情况的图。
OC对象本质:属性和方法
property:自动生成成员变量,添加get 、 set方法。
但是我们通过clang转化c++后发现,实例对象中只对属性添加了成员变量,方法不存在。得出结论:实例的方法不存在实例对象中,存在类对象的方法列表中。原因是方法不变,存在方法列表中。后面还会再讲到。
3、OC对象内存布局?
iOS是小端模式,也就是内存是从高到低依次读取。
内存是连续一块地址。首先isa占8个字节,然后依次是自己属性开辟的空间。
内存对齐:结构体的最终大小必须是最大成员大小的倍数。其中最大成员是isa也就是8字节。
我们继承对象时候,比如OC对象A占16字节,实际使用12字节。B继承A并且B有自己一个4字节的int age 成员,那么b对象实际开辟的内存大小仍然是16 字节。因为A对象的16字节找实际使用12还有4字节未用,正好给int age 的4字节使用了。
打印对象空间大小
%zd class_instance;
%zd mallocsize(); 没写完整,只是核心点
网友评论