一、代码转换
1、 添加 NSObject 对象
如在 main.m 添加一个 NSObject 对象(或者直接复制以下代码到 main.m 文件中):
#import <Foundation/Foundation.h> #import <objc/runtime.h> #import <malloc/malloc.h> int main(int argc, char * argv[]) { @autoreleasepool { NSObject *obj = [[NSObject alloc] init]; } return 0; }
2、命令行实现
已知:
1、不同平台支持的代码是不一样的( Windows、mac、iOS)
2、iOS架构:模拟器(i386)、32bit(armv7)、64bit(arm64)
命令行格式如下:
// 不指定平台和架构 clang -rewrite-objc main.m -o main.cpp // 指定真机(ios平台64bit架构) xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp // 指定模拟器 xcrun -sdk iphonesimulator clang -arch i386 -rewrite-objc main.m -o main-i386-simulator.cpp // 命令行格式 // xcrun:xcode run // -sdk 平台:iphoneos // -arch 架构:arm64 // -rewrite-objc:重写OC // main.m -o main-arm64-1.cpp:OC源文件 -o 输出的CPP文件 // 如果需要链接其他框架,使用-framework参数。比如-framework UIKit xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
执行生成目录:
chenzimin@rattanchen InterView % tree . ├── Info.plist ├── main-arm64-iphoneos.cpp ├── main-i386-simulator.cpp ├── main.cpp └── main.m 0 directories, 5 files
3、结果
main 方法中转化的代码依次如下:
1、不指定机型架构:
2、指定机型架构:
以上直观的感知转cpp的代码是一样的,但是不配置机型机构的部分,因为需要涉及兼容问题,代码行数相差了将近三倍。所以按机型配置可以节省很多存储空间。
二、本质分析
看到OC实现和 C\C++ 底层实现,如下:
结论:
1、NSObject 对象在内存中就是一个结构体(结构体优势:可以兼容不同种数据类型)。
2、Class:是指向结构体的指针。
3、指针占位大小:64位环境占8个字节(下面默认按64位系统计算),32位环境占4个字节。
4、而 NSObject_IMPL 只有一个成员对象,那么 isa 成员的地址就是结构体在内存中的地址,占8个字节。
NSObject *obj = [[NSObject alloc] init]; 代码解读:
// 1、创建好一个对象并给这个对象分配内存地址,假设地址为:0x100400110 [[NSObject alloc] init]; // 2、设置一个指针 *obj NSObject *obj; // 3、让 *obj 指针指向/存储这个对象的内存地址。 NSObject *obj = [[NSObject alloc] init];
图如下:
三、NSObject 是有多少内存呢?
继续以上例子,已知有两个方法可以获取内存分配空间:
#import <objc/runtime.h> #import <malloc/malloc.h> // 获得NSObject实例对象的成员变量所占用的大小 >> 8 NSLog(@"%zd", class_getInstanceSize([NSObject class])); // 获得obj指针所指向内存的大小 >> 16 NSLog(@"%zd", malloc_size((__bridge const void *)obj));
为什么一个返回8字节,另一个返回16字节。注意了,它们虽然都是获取占用内存大小。但是获取对象不一样。
class_getInstanceSize 方法获取的是实例对象的成员变量所占用的大小。
malloc_size 获取的是指针所指向的内存大小。
那为什么指针所指向的内存会更大呢?这时可以查看一下OC底层原码是如何分配内存的,如下:
size_t instanceSize(size_t extraBytes) { size_t size = alignedInstanceSize() + extraBytes; // CF requires all objects be at least 16 bytes. if (size < 16) size = 16; return size; }
可以看到,当分配内存小于16位时,直接设置16,这是他们底层的规定。
结论:
1、系统分配了16个字节给 NSObject 对象(通过malloc_size函数获得)
2、但 NSObject 对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得)
四、Demo