OC对象内存布局与isa指针

一、Objective-C的本质

  • Objc的底层实现是C\C++代码:objc->C\C+±>汇编->机器语言
  • Objc的对象,类主要是基于C\C++中的结构体实现
  • 将Objc代码转换为C\C++代码
xcrun  -sdk  iphoneos  clang  -arch  arm64  -rewrite-objc OC源文件  -o  输出的CPP文件

二、一个objc对象如何进行内存布局?考虑父类的情况

类结构图:
请添加图片描述

对象的底层实现

  • oc的代码
@interface Person : NSObject
{
    @public
    int _age;
}
@end

@interface Student : Person
{
    @public
    int _no;
}
@end

@interface Graduate : Student
{
    @public
    int grade;
}
@end

@implementation Graduate

@end

对应的C++代码

struct NSObject_IMPL {
    Class isa;
};

struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS; // 8
    int _age; // 4
};

struct Student_IMPL {
    struct Person_IMPL Person_IVARS; 
    int _no; 
}; 


 Student *stu = [[Student alloc] init];
 stu->_age = 2;
 stu->_no = 3;
 NSLog(@"stu - %zd", class_getInstanceSize([Student class]));  // 16
 NSLog(@"stu - %zd", malloc_size((__bridge const void *)stu)); // 16

 Graduate *grade = [[Graduate alloc] init];
grade->_age = 7;
grade->_no = 8;
grade->grade = 9;
NSLog(@"grade - %zd", class_getInstanceSize([Graduate class])); // 24
NSLog(@"grade - %zd", malloc_size((__bridge const void *)grade)); // 32
  • 64位系统下, 可以看出,编译给Person分配了16个字节,实际用到12个字节,还有4个字节没有使用, Student对象继承Person对象,Student对象实际会继续使用Person对象内存中没有使用的4个字节,所以Student对象的内存大小是16个字节,Grade继承Student类,实际占用的内存大小为20个字节,由于内存对齐原因,以8个字节内存对齐,所以会使用24个字节,编译器分配了32个字节
  • 内存对齐:结构体的大小必须是最大成员大小的倍数

Student内存布局.png

总结:

  • 就是多了一个isa指针,isa的大小由编译器,系统决定,内存分配编译器按照内存对齐进行大小分配,分配的内存,不一定会完全用完
    class_getInstanceSize获取实例对象至少占用的内存
    malloc_size获取编译器给实例对象对象分配的内存的大小
    在 libmalloc源码中定义了 #define NANO_MAX_SIZE 256 /* Buckets sized {16, 32, 48, 64, 80, 96, 112, …}表示在iOS系统中每次最少分配16个字节,或者每次分配的字节数是16的倍数,每次最多分配256字节

三、一个objc对象的isa指针指向什么?有什么作用

  • 实例变量的isa指针指向他所属的类
  • 类的isa指针指向他所属的原类
  • 原类的根类的isa指针指向他本身
  • 当我们向对象发送消息时,可以根据isa指针指向寻找原类的方法列表是否存在这个消息,确定是否可以响应方法,作用就是帮我们寻找方法

四、objc对象的类方法和实例方法有什么本质区别和联系?

  • 区别:
  1. 属于谁
    类方法属于类对象 [NSString stringwithFormat:]
    实例方法属于实例对象 [str length]

  2. 谁调用
    类方法 类对象调用
    实例方法 实例对象调用

  3. self是什么
    在类方法里面,self表示类对象
    在实例方法里,self表示实例对象

  4. 是否可以访问成员变量
    类方法里 不可以访问成员变量
    实例方法 可以访问成员变量

  5. 方法调用问题
    类方法里 可以调用实例方法也可以调用类方法
    实例方法里 继可以调用实例方法也可以调用类方法

猜你喜欢

转载自blog.csdn.net/guoxulieying/article/details/132016705