美文网首页
OC对象的本质

OC对象的本质

作者: 冰棍儿好烫嘴 | 来源:发表于2023-03-14 21:11 被阅读0次

    我们平时编写的Objective-C代码,底层实现其实都是C/C++代码


    所以Objective-C的面向对象都是基于C/C++的数据结构实现的。
    Objective-C的对象、类是基于C/C++的结构体数据结构实现的。
    将Objective-C代码转换为C/C++代码(需要用到clang编译器)
    在终端一直cd到想要转为cpp文件的所在位置,然后敲命令行

    clang -rewrite-objc main.m -o main.cpp
    

    将main.m文件转为main.cpp文件,因为平台不同支持的代码肯定不一样,例:windows、Mac、iOS等,这里主要讨论iOS平台,所以用如下命令行

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

    NSObject的底层实现


    Class isa里边的Class是一个指向结构体的指针。

    runtime里边有一个获取实例实际大小的方法,如下

    #import <objc/runtime.h>
    NSObject *obj = [[NSObject alloc] init];
    //获得NSObject实例对象的成员变量所占用的大小 >> 8
    num = class_getInstanceSize([NSObject class]);
    NSLog(@"%zd",num);//无符号的打印方式
    打印结果为8
    

    malloc里边有一个获取开辟内存大小的方法,如下

    #import <malloc/malloc.h>
    NSObject *obj = [[NSObject alloc] init];
    //获得obj指针所指向内存的大小>>16
    num = malloc_size((__bridge const void *)obj);
    NSLog(@"%zd",num);
    打印结果为16
    

    opensource源码下载

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

    系统分配了16个字节给NSObject对象(通过malloc_size函数获得),但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得)

    NSObject *obj = [[NSObject alloc] init];
    下断点,然后实时查看内存数据
    

    实时查看内存数据方法:
    Debug-> Debug Workflow -> View Memory (Shift + Command + M)

    也可用lldb指令查看内存:
    常用lldb指令
    print、p:打印
    po:打印对象

    • 读取内存:
      memory read/数量格式字节数 内存地址
      x/数量格式字节数 内存地址

    • 修改内存中的值
      memory write 内存地址 数值
      memory write 0x0000010 10

    • 格式
      x是16进制,f是浮点,d是10进制

    • 字节大小
      b:byte 1字节,h:half word 2字节
      w:word 4字节,g:giant word 8字节




    现在研究一下自定义的对象(有新的成员属性)占用的内存
    在main.m文件中新建一个继承NSObject的Student类,然后写两个int类型的成员变量,再把main.m文件转成c++文件

    @interface Student : NSObject
    {
        @public
        int _no;
        int _age;
    }
    @end
    @implementation Student
    @end
    
    Student *student = [[Student alloc] init];
    

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
    在cpp文件中发现

    struct NSObject_IMPL{
        Class isa;
    }
    struct Student_IMPL{
        struct NSObject_IMPL NSObject_IVARS;
        int _no;
        int _age;
    };
    
    Student *student = [[Student alloc] init];
    student->_no = 4;
    student->_age = 5;
            
    NSLog(@"%zd",class_getInstanceSize([Student class]));//16
    NSLog(@"%zd",malloc_size((__bridge  const void *)student));//16
    

    再用实时查看内存数据的方法去查看,先在lldb中打印出student的首地址,p student,然后把对象的首地址在debug -> debug workflow -> view memory中显示内存数据。如下图:

    大端小端模式:

    思考:一个Person对象、一个Student对象占用多少内存空间?

    @interface Person : NSObject
    {
        @public
        int _age;
    }
    @end
    @implementation Person
    @end
    
    @interface Student : Person{
        @public
        int _no;
    }
    @end
    @implementation Student
    @end
    
    Person *person = [[Person alloc] init];
    Student *stu = [[Student alloc] init];
            
    NSLog(@"Person -- %zd",class_getInstanceSize([Person class]));//16  class_getInstanceSize内存对齐过的占用的大小
    NSLog(@"Person -- %zd",malloc_size((__bridge  const void *)person));//16
    NSLog(@"Student -- %zd",class_getInstanceSize([Student class]));//16
    NSLog(@"Student -- %zd",malloc_size((__bridge  const void *)stu));//16
    

    方法不在实例对象内存里边,所以方法不占用内存,只有成员变量和属性影响内存的大小。方法放在什么地方???(后边研究再补充:类对象的方法列表里边)

    2个容易混淆的函数

    • 创建一个实例对象,至少需要多少内存?
    #import <objc/runtime.h>
    class_getInstanceSize([NSObject class])
    
    • 创建一个实例对象,实际上分配了多少内存?
    #import <malloc/malloc.h>
    malloc_size((__bridge  const void *)obj);
    

    相关文章

      网友评论

          本文标题:OC对象的本质

          本文链接:https://www.haomeiwen.com/subject/nwckrdtx.html