(一)OC对象在底层中的布局
我们平时编写的Objective-C
代码,在底层都是使用C/C++
实现。
即Objective-C
-> C/C++
-> 汇编语言
-> 机器语言
。
我们定义个NSObject
对象
NSObject *object = [[NSObject alloc] init];
使用终端命令将OC
代码转换成iOS能支持的C/C++
代码;
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc 'OC源文件' -o '输出的CPP文件'
通过阅读转换后的.cpp
文件,可以找到一个名为 NSObject_IMPL
的结构体。分析结构体名字实际含义是 NSObject Implementation
struct NSObject_IMPL {
Class isa;
};
因此我们可以知道OC对象在底层的布局是一个结构体
。
(二)对象在内存中的占用大小
引入<objc/runtime.h>
, 使用 class_getInstanceSize
方法可获取NSObject
实例对象的 成员变量
所占用的大小,可以观察到返回 8 个字节
class_getInstanceSize([NSObject class])
引入<malloc/malloc.h>
, 使用malloc_size
方法获取指针所指向的内存大小
,可以观察到返回16
个字节。
malloc_size((__bridge const void *)(object));
通过阅读Objc源码 可得知在alloc
一个对象时,CoreFunction
框架硬性规定分配内存空间不小于16
个字节
总结:
系统分配了
16
个字节给NSObject
对象(通过malloc_size
函数获得),但NSObjec
t对象内部只使用了8
个字节的空间(64bit环境下,可以通过class_getInstanceSize
函数获得)
(三)通过XCode工具分析内存
首先打印NSObject
对象地址,通过工具ViewMemory
查看。
可观察到前16
个字节中,只有8
个字节存在数据(存放isa
指针)
(四)自定义类内存分析
定义Student
类,初始化。通过重复之前步骤,可观察到底层实现。
struct Student_IMPL {
Class isa;
int _no;
int _age;
};
@interface Student : NSObject
{
@public
int _no;
int _age;
}
@end
@implementation Student
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *stu = [[Student alloc] init];
stu->_no = 4;
stu->_age = 5;
NSLog(@"%zd", class_getInstanceSize([Student class]));
NSLog(@"%zd", malloc_size((__bridge const void *)stu));
}
return 0;
}
通过使用class_getInstanceSize
与malloc_size
方法可观察到占用16
个字节存储空间。
使用
ViewMemory
查看前8
个字节存放isa
,_no
与_age
分别占用4
个字节。
我们也可以使用LLDB
指令打印相关地址信息
,并且可使用memory write
指令直接修改内存中的数据
可以观察到将
_no
中的值修改为了8
。
(五)继承类的内存占用分析
@interface Person : NSObject
{
@public
int _age;
}
@end
@implementation Person
@end
@interface Student : Person
{
int _no;
}
@end
@implementation Student
@end
分析:Person
类中isa
指针占用8
个字节,_age
占用4
个字节。通过CoreFunction
框架硬性规定分配内存空间不小于16个字节
。得知共占用16
个字节。
但是
即使无此硬性规定,通过内存对齐
规则:结构体的最终大小,必须是最大成员的倍数。
。
Student
类占用16
个字节。isa
占用8
个字节,_age
占用4
个字节,剩余4
个字节,被_no
占用。
网友评论