iOS学习-OC对象的本质 01

2020-05-28  本文已影响0人  快乐的tomato

先看1个问题

1、一个NSObject对象占用多少内存?

一、NSObject 类

oc代码的底层是C/C++代码
oc的面向对象其实都是基于C/C++的数据结构实现的:


image.png

怎么将oc代码转换为C/C++代码?
转成iOS平台的代码

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc oc源文件 -o 输出的cpp文件

转换一下main.m文件
1、打开终端,cd 到main.md的文件所在文件夹
2、运行命令 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp


image.png

最后生成一个.cpp文件


image.png

main函数变成了下面的代码

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class")));


        NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
 
    }
    return UIApplicationMain(argc, argv, __null, appDelegateClassName);
}

也可以直接点进去看

@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}

所以 [[NSObject alloc] init] 底层实现是长得这样子,就是一个结构体,一个结构体里就只有一个指针,所以占8个字节

struct NSObject_IMPL {
    Class isa;//占8个字节
};

图示


image.png
二、自定义的类

-如果是一个自定义的类Student

#import <objc/runtime.h>
#import <malloc/malloc.h>
@interface Student : NSObject
{
    @public
    int _no;//4
    int _age;//4
    int _grade;//4
}8+12=20    24
多出来的4个字节,好像是计算机内存对齐产生的
@end
@implementation Student
@end
int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
        
        Student *xiaoming = [[Student alloc] init];
        xiaoming->_age = 4;
        xiaoming->_no = 5;
        xiaoming->_grade = 98;
       

        NSLog(@"Student类实例对象的成员变量所占用的大小:🍎%zd",class_getInstanceSize([Student class]));
        NSLog(@"xiaoming指针所指向内存的大小:🍎%zd",malloc_size((__bridge const void *)(xiaoming)));
        
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

image.png

又加了几个成员变量,打出的结果不一样

student对象的本质.png

假如一个Person对象继承自NSobject,Student 继承自Person,那么Person 和Student分别占用的内存是多少?


image.png

Student应该占用20个字节,为啥最后是16个字节,这是因为内存对齐造成的, _no的4个字节占用了Person空出来的4个字节


三、另外一种方式窥探

Class 是一个指针
现在我们来看第一个问题

#import <objc/runtime.h>
#import <malloc/malloc.h>

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
        
        NSObject *obj = [[NSObject alloc] init];
        NSLog(@"NSObject类实例对象的成员变量所占用的大小:8字节🍎%zd",class_getInstanceSize([NSObject class]));
        NSLog(@"obj指针所指向内存的大小:16字节🍎%zd",malloc_size((__bridge const void *)(obj)));
        
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

image.png

结果:


image.png

感觉红框中的其实就是 isa 指针
现在可以回答开篇的第1个问题:

一个指针变量所占用的大小(64bit环境下,8个字节,32bit环境下,4个字节)


Printing description of obj:
<NSObject: 0x60000364c130>
(lldb) p obj
(NSObject *) $7 = 0x000060000364c130
(lldb) po obj
<NSObject: 0x60000364c130>

(lldb) memory read 0x60000364c130
0x60000364c130: 00 2d be 89 ff 7f 00 00 00 00 00 00 00 00 00 00  .-..............
0x60000364c140: c8 fa a5 87 ff 7f 00 00 e4 85 22 6c 42 ae 26 a2  .........."lB.&.
(lldb) 


上一篇下一篇

猜你喜欢

热点阅读