美文网首页
iOS相关知识(二)--- 内存相关

iOS相关知识(二)--- 内存相关

作者: 奋斗的小马达 | 来源:发表于2021-09-17 09:59 被阅读0次

    OC 对象的本质

    例:有Person对象 Person继承与NSObject ,有Student对象 Student继承Person。代码以及解析如下:

    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    #import <malloc/malloc.h>
    
    @interface Person : NSObject
    {
        @public
        int _age;
        
    }
    @end
    
    @implementation Person
    
    @end
    
    
    @interface Student : Person
    {
        @public
        int _no;
        int _hight;
    
    }
    @end
    
    @implementation Student
    
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            /**
             平时编写的 Objective - C 代码,底层实现其实都是C\C++代码
             所以Objective- C的面向对象都是基于C\C++的数据结构实现的
             Objective- C的对象、类主要是基于C\C++的结构体来实现的
             所有的对象 苹果硬性规定 至少占用16个字节 (如果占用内存小于16 则直接返16个字节)
             int         类型 4个字节
             double  类型 8个字节
             float      类型8个字节
             string    类型8个字节
             number 类型8个字节
             
             生成c++文件命令
             xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc (要生成的文件) -o (生成后的文件)
             
             iOS在分配内存的时候最后得到的都是16的倍数
    
             */
            
            // 问题1  一个NSObject对象占用多少内存?
            NSObject * obj = [[NSObject alloc]init];
            
            //获得NSObject类的实例对象的成员变量所占用的存储空间(并不是真正占用内存的大小) :8
            NSLog(@"%zd",class_getInstanceSize([NSObject class]));
        
            //获得obj指针所指向的内存的大小 :16
            NSLog(@"%zd",malloc_size((__bridge const void *)(obj)));
            
            
            // 问题2  Person对象占用多少内存?
            
            Person *person = [[Person alloc]init];
            person->_age = 10;
            NSLog(@"%zd",malloc_size((__bridge const void *)(person)));
            /**
             答案 16
             分析:Person 转化成C++是他的本质是一个结构体 如下所示:
             
             struct Person_IMPL {
                 struct NSObject_IMPL NSObject_IVARS;
                 int _age;
             };
             
             struct NSObject_IMPL NSObject_IVARS; 又是一个指针指向NSObject 也是一个结构体 如下所示
             
             struct NSObject_IMPL {
                 Class isa;
             };
             
             所以 Person 最终的结构体 可以理解为如下(这种方式不严谨)
             struct Person_IMPL {
                 Class isa;
                 int _age;
             };
             
             所以占用内存为  8 + 4 = 12   但是由于 苹果硬性要求 一个对象最低占用16个字节 所以  Person对象占用内存为 16个字节
    
             */
    
            
            // 问题3  Student对象占用多少内存?
            Student *stu = [[Student alloc]init];
            stu->_no = 20;
            stu->_age = 30;
            stu->_hight = 180;
    
            NSLog(@"%zd",malloc_size((__bridge const void *)(stu)));
            
            /**
             答案 32
             分析:Student 转化成C++是他的本质是一个结构体 如下所示:
             
             struct Student_IMPL {
                 struct Person_IMPL Person_IVARS;
                 int _no;
             };
             
             struct Person_IMPL Person_IVARS;  也是一个结构体 如下所示
             
             struct Person_IMPL {
                 struct NSObject_IMPL NSObject_IVARS;
                 int _age;
             };
             
             
             struct NSObject_IMPL NSObject_IVARS; 又是一个指针指向NSObject 也是一个结构体 如下所示
             
             struct NSObject_IMPL {
                 Class isa;
             };
             
             
             所以 Student 最终的结构体 可以理解为如下(这种方式不严谨)
             struct Person_IMPL {
                 Class isa;
                 int _age;
                 int _no;
                 int _hight;
    
             };
             
             所以占用内存为  8 + 4 + 4 + 4 = 20 但是iOS系统分配空间的时候是根据实际需要的大小来分配一块相近16倍数的空间  所以 Student对象占用内存为 32个字节 (证据来源于苹果底层源代码 cmalloc 函数)
             */
    
        }
    
        return 0;
    }
    
    

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

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

    2、OC 对象分为几种?

    答:OC对象分为三种,分别为 instance对象(实例对象)、class对象(类对象)、 meta-class对象(元类对象)
    
    instance对象(实例对象)
    通过alloc 创建的对象都是实例对象 如
    NSObject *objc = [[NSObject alloc]init];
    objc 就是实例对象
    instance对象在内存中存储的信息主要包括
    isa指针
    其他成员变量
    
    class对象(类对象)
    获取类对象的方法有以下三种
    Class objcClass1 = [objc class];
    Class objcClass2 = [NSObject class];
    Class objcClass3 = object_getClass(objc);
    
    每个类在内存中有且只有一个class对象
    
    class对象在内存中存储的信息主要包括:
    isa指针
    superclass指针
    类的属性信息(@property)
    类的对象方法信息(instance method)
    类的协议信息(protocol)
    类的成员变量信息(ivar)
    

    meta-class对象(元类对象)

    获取元类对象 直接将类对象传进去 就获得了元类对象
    Class objectMetaClass = object_getClass ([NS0bject class]);
    
    每个类在内存中有且只有一个meta-class对象
    
    meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中
    
    存储的信息主要包括:
    isa指针
    superclass指针
    类的类方法信息(class method。也就是+开头的方法)
    

    注意:实例对象里面的成员变量和类对象的里面的成员变量是有区别的

    实例对象的成员变量存放的是变量的值 比如 int a = 8  他存放的就是8 这个值
    
    类对象的成员变量存放的是变量的信息 比如 变量的类型、变量的名称
    
    原因是:一个对象可以创建很多实例对象,但是他有且只有一个类对象和一个元类对象
    @interface Student : Person
    {
        @public
        int _no;
        int _hight;
    
    }
    @end
    
    @implementation Student
    
    @end
    
    这个Person 可以创建很多实例变量如下所示:
            Person *person1 = [[Person alloc]init];
            Person *person2 = [[Person alloc]init];
            Person *person3 = [[Person alloc]init];
            ...
    person1、person2、person3 都是 Person类的实例对象 每个实例对象都有 _no和_hight的值 他们互不影响,所以在内存中存在多份。
    但是 int _no、int _hight 这些变量的名称和类型永远只存在一份,所以存放在类对象中。
    

    3、对象的isa指针指向哪里?流程如图所示: isa指针.png

    instance(实例对象)对象的isa指向class对象
    class(类对象)对象的isa指向meta-class对象
    meta-class(元类)对象的isa指向基类的meta-class对象
    

    4、OC的类信息存放在哪里?

    成员变量的具体值,存放在instance对象
    对象方法、属性、成员变量、协议信息,存放在class对象中
    类方法,存放在meta-class对象中
    

    5、isa、superclass总结

    instance的isa指向class
    
    class的isa指向meta-class
    
    meta-class的isa指向基类的meta-class
    
    class的superclass指向父类的class
    如果没有父类,superclass指针为nil
    
    meta-class的superclass指向父类的meta-class
    基类的meta-class的superclass指向基类的class
    
    instance调用对象方法的轨迹
    isa找到class,方法不存在,就通过superclass找父类
    
    class调用类方法的轨迹
    isa找meta-class,方法不存在,就通过superclass找父类
    
    
    isa和superclass指向流程.png

    相关文章

      网友评论

          本文标题:iOS相关知识(二)--- 内存相关

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