问题:一个NSObject对象占用多少内存
编译过程
由编译过程可知Objective-c的面对对象都是基于 C\C++的数据结构来实现的,那首先弄清楚 Objective-c的对象、类主要基于 C\C++的什么数据结构来实现的?
将Objective-c代码转换成 C\C++的代码
Objective-c代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *objc = [[NSObject alloc] init];
}
return 0;
}
转换命令:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
xcrun -sdk 平台 clang -arch 架构 -rewrite-objc 源文件 -o 输出文件
平台: windows,macos,os;不同平台支持的代码肯定不一样
架构:模拟器(i386),32bit(armv7),64bit(arm64)
如果需要链接其他框架,使用-framework参数(比如-framework UIKit)
在代码中找到 NSObject的C++实现
struct NSObject_IMPL {
Class isa;
};
也就是NSObject类的Objective-c到 C++的实现是
NSObject类的Objective-c到 C++的实现
从中看出NSObject的C++实现是一个结构体,成员只有一个 class 类型的 isa,来看看 class 类型的实现
typedef struct objc_class *Class;
class 是 指向结构体类型的指针,也就是NSObject的C++实现是一个结构体,只包含一个指针类型的成员
指针类型内存大小:在32bit 是4个字节,在64bit 是8个字节
由此可知NSObject的C++实现的结构体内存大小是8个字节
假设 isa 的地址:0x100400110,那NSObject的C++实现的结构体地址也是0x100400110,也就是NSObject对象的地址也是0x100400110
NSObject对象地址
初步得出结论:一个NSObject对象占用8个字节
现在用class_getInstanceSize和malloc_size两个方法来打印下返回大小
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *objc = [[NSObject alloc] init];
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
NSLog(@"%zd", malloc_size((__bridge const void *)objc));
}
return 0;
}
打印结果:
2018-08-24 17:23:05.944980+0800 interview01-OC对象的本质[51693:837247] 8
2018-08-24 17:23:05.945510+0800 interview01-OC对象的本质[51693:837247] 16
可以看见malloc_size的结果是16,与NSObject的C++实现的结构体内存大小是8个字节不一致。
从苹果开源网站(opensource.apple.com)找到源码来看看class_getInstanceSize和malloc_size两个方法的不同
objc4
class_getInstanceSize
看看
alignedInstanceSize()的实现
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
Class's ivar size rounded up to a pointer-size boundary.翻译过来就是返回类的成员变量的内存大小
allocWithZone
_objc_rootAllocWithZone
class_createInstance
_class_createInstanceFromZone
instanceSize
CF requires all objects be at least 16 bytes.翻译过来就是一个 oc 对象最少16个字节
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *objc = [[NSObject alloc] init];
// 获取NSObject实例对象的成员变量所占用的大小:8
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
// 获取objc指针所指向分配内存的大小:16
NSLog(@"%zd", malloc_size((__bridge const void *)objc));
}
return 0;
}
答案:
系统分配了16个字节给 NSObject对象(通过 malloc_size 函数获得)
但NSObject对象内部只使用了8个字节的空间(64bit 环境下,通过 class_getInstanceSize 函数获得)
从内存的角度来窥探本质
断点打印 objc 的内存地址
可以看到对象 objc 的地址是0x100450eb0,进入View Memory 工具查看内存
View Memory
View Memory
数据格式
数据格式说明:
- 最左边红色框内显示的是内存地址
- 地址以十六进制表示编号,内存的基本单位是字节(8bit)
- 每一个字节对应一个地址
- 系统分配内存的逻辑,分配的内存大小时赋值
00,初始化的时候再具体赋值
可以看到0x100450eb0分配的内存明显是41 31 FC B3 FF FF 1D 00 00 00 00 00 00 00 00 00,也就是16个字节,但真正利用起来的只有8个字节。
拓展lldb 命令
- print、p:打印
- po:打印对象
- 读取内存
memory read/(数量)(格式)(字节)
x/(数量)(格式)(字节)
格式:x是16进制,f是浮点,d是10进制
字节大小:b:byte 1字节,h:half word 2字节,w:word 4字节,g:giant word 8字节
读取`0x100450eb0`开始的4个8字节16进制的内存
读取`0x100450eb0`开始的3个4字节10进制的内存
- 修改内存中的值
memory write 内存地址 数值
修改`0x100450eb9`的值为4














网友评论