OC的本质

那年仲夏 提交于 2019-12-22 13:57:25

1.OC的本质是什么?

OC的对象和类是基于C/C++的结构体来实现的。OC的代码转换过程如下:

OC->C/C++ ->汇编语言 -> 机器语言。

2.如何查看OC的代码转成了C/C++的代码呢?

例如创建了一个工程,名字为OC-01,编写代码如下:

@interface Student : NSObject

@end

@implementation Student

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
       
        Student *stu = [[Student alloc] init];
    }
    return 0;
}

启动命令行,切换路径到main.m所在的文件下,如下图:

回车,进入文件夹后,输入如下的字符串:

 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp

解释:

xcrun---表示xcode 执行

iphoneos -- 表示苹果手机平台

-arch arm64 -- 表示架构为arm64

-rewrite-objc -- 表示重写objc的代码

main.m -- 表示要转成C++的文件

-o  --表示输出

main.cpp --  表示转成的文件名称(格式为:名称.cpp)

回车之后,就可在main.m的文件夹下可以看到main.cpp:

点击查看即可。

3.OC对象如何在内存中布局?

首先查看OC的定义如下:

@interface NSObject {
    Class isa;
}

而NSObject的底层实现如下:

struct NSObject_IMPL {
	Class isa;
};

而Class的定义如下:

typedef struct objc_class *Class;

从而可以知道,isa是一个objc_class类型的结构体指针,而指针在64位系统中,占用8个字节,32位系统中,占用4个字节。

当一个对象alloc时,会自动分配内存空间,而对象的第一属性就是isa指针,所以,对象的内存就指向了第一个属性地址,即isa地址。

4.一个NSObject对象占用多少内存?

从第3个问题中,我们可能猜想一个NSObject对象的内存大概是8个字节,我们可以用class_getInstanceSize和malloc_size这两个函数来查看内存分配的大小。

首先,引入 #import <objc/runtime.h> 来调用class_getInstanceSize;

如下图:

用class_getInstanseSize这个方法得出的结果是8个字节;

但是,导入头文件:#import <malloc/malloc.h> 方便调用malloc_size()这个方法,如下图:

这个方法获取到的内存大小是16.

所以,内存到底是8还是16呢?

去查看class_getInstanceSize的底层代码如下:

查看alignedInstanceSize的源码如下:

官方解释,就是alignedInstanceSize这个方法返回的是一个类其成员变量所占用的内存大小。

总结如下:

一个NSObject对象,会分配16个字节的内存,但是占用的内存只有8个字节。

补充:

指针占用8个字节,基础数据类型占用4个字节,那么一个基于NSObject的对象,有一个字符串类型的name,一个int类型的age,那么属性占用的内存应该是:isa指针的内存+name指针的内存+age的内存 = 8+8+4 = 20,但是实际上是24。这是因为苹果底层采用的内存对其的方法,也就是说分配的内存永远是8的倍数,如果没有到8的倍数,就自动补齐。

如果此时,再添加一个int类型的height,那么其内存大小也是24.

疑问:

为什么NSObject对象内部只占用了8个字节,但是却分配了16个字节的空间呢?我们去查看创建内存的源码,如下:

点击查看instanceSize的源码如下:

官方解释就是,coreFoundation要求所有的object对象至少都要分配16个字节的内存。所以,虽然只占用了8个字节的内存,但是还是会分配16个字节。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!