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

OC 对象的本质

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

#import 
#import 
#import 

@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相关知识(二)--- 内存相关)