美文网首页程序员
二:类的内存结构分析

二:类的内存结构分析

作者: Mr姜饼 | 来源:发表于2020-11-11 18:02 被阅读0次

上小节回顾:
*上节课我们介绍实例化对象的内存分部,其中包含了isa指针内存和其属性,其中isa指针中存储了非常重要的shiftCls字节码(33字节or44字节),另外也学到结构体的字节对齐和类对象的字节对齐

本节知识点:
研究学习类本身的内存结构分布


  • 开始:

,实例化对象objc1的内存我们知道其首isa指针存储了我们的类信息,并且我们上节内容也得到了证实

  • 提出猜想:

如果我们继续往下探索,继续探索Cls的内存分部情况呢,我们会得到什么呢

  • 研究实施:

    我们依次往下进行四个步骤,当发现走到第三部的时候,已经开始循环了

ps:lldb输出语句
x :查看内存结构 !
x/4gx:输出4条16进制的数据
p:查看地址
p/x:查看16进制的地址

image.png

步骤1:
我们得到类对象的isa内存,并且与面具MASK进行与算,得到 shiftCls信息,并且打印得到我们的LGPerson
步骤2:
接着我们拿到LGPerson类本身进行内存结构查看,同样的我们通过isa内存与面具MASK进行“与”运算,拿到结果我们输出打印,得到的还是LGPerson,而此时的地址却与第一步得到的不同,那么此isa指针指向的又是什么东西呢?
步骤3:
我们拿到上一步得到的LGPerson类本身进行内存结构查看,同样的我们通过isa内存与面具MASK进行“与”运算,拿到结果我们输出打印,得到的是NSObject,那么此isa指针指向的又是什么东西呢?
步骤4:
我们拿到上一步得到的NSObject类本身进行内存结构查看,同样的我们通过isa内存与面具MASK进行“与”运算,拿到结果我们输出打印,得到的依然是NSObject,而此时的地址却与上一步得到的一模一样,此时isa指针地址指向的又是什么呢。

  • 得出结论:

isa的指针流程图:
实例化对象(objc1) ->1. 类(Person)- > 2.元类(Person)-> 3.根元类(NSObject) ->4.根元类(NSObject)


属性&成员变量&实例变量


@interface LGPerson : NSObject
{
    NSString* interst;
    
}
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, strong) NSString *name;


//实例化方法
- (void)test_InstanceMethod;
//类方法
+ (void)test_ClassMethod;
@end

属性&成员变量&实例变量的区别:

属性 = 带下划线成员变量 + setter + getter ⽅法

实例变量 : 特殊的成员变量 (类的实例化)


小节课题:通过lldb来获取类的属性和方法:


@interface LGPerson : NSObject
{
    NSString* interst;
    
}
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, strong) NSString *name;


//实例化方法
- (void)test_InstanceMethod;
//类方法
+ (void)test_ClassMethod;
@end

  • step1:首先分析源码来得到的内存结构
  • 源码分析

objc_object:

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

objc_class:

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const {
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

    void setInfo(uint32_t set) {
        ASSERT(isFuture()  ||  isRealized());
        data()->setFlags(set);
    }
    .
    .//此处省略(以上才是重点)
    .
}

:

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint16_t witness;
#if SUPPORT_INDEXED_ISA
    uint16_t index;
#endif

    explicit_atomic<uintptr_t> ro_or_rw_ext;

    Class firstSubclass;
    Class nextSiblingClass;

    .
    .//此处省略
    .

    const class_ro_t *ro() const {
        auto v = get_ro_or_rwe();
        if (slowpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>()->ro;
        }
        return v.get<const class_ro_t *>();
    }

    void set_ro(const class_ro_t *ro) {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            v.get<class_rw_ext_t *>()->ro = ro;
        } else {
            set_ro_or_rwe(ro);
        }
    }

    const method_array_t methods() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->methods;
        } else {
            return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
        }
    }

    const property_array_t properties() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>()->baseProperties};
        }
    }

    const protocol_array_t protocols() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->protocols;
        } else {
            return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
        }
    }
};

初步小结:
取属性objc_class -> class_data_bits_t -> class_rw_t -> properties
取方法objc_class -> class_data_bits_t -> class_rw_t -> methods

image.png
  • step2:手动操作实现

image.png

分析:
step1:拿到LGPerson的类内存分部,即objc_class的内存,
step2:内存地址指针平移“32”字节0x0000000100002258>0x0000000100002278,即取到了class_data_bits_t的字节内存,注意这里为什么是平移32字节,其原因是因为 Class ISA + Class superclass + cache_t cache 为32字节,再利用指针平移的思路,即能拿到 class_data_bits_t的首地址指针 **
step3:
取出class_rw_t内容
step4:取出properties内容
step5:
取出propertieslist内容
step6:取出list中的第0个位置的属性
step7:取出list中的第1个位置的属性
step8:取出list中的第2个位置的属性,程序发生崩溃,我们发现并没有把成员变量interest取出来,思考????

image.png

分析:

step1:取出class_rw_t中的methods内容
step2:取出methodslist内容
step3:
取出list中的第0个位置的属性**
step4:取出list中的第1个位置的属性
.
.
.
思考:我们发现打印中并没有找到类方法 "test_ClassMethod" ????


问题解决:1.成员变量到底在哪查看呢?

我们可以objc_class -> class_data_bits_t -> class_rw_t -> ro -> ivars中查找

image.png
image.png

总结:
在 "ivars" 中,我们既可以找到成员变量 也可以找到 属性 成员


问题解决:2.类方法到底在哪查看呢?

猜想:
是不是类方法根本就不存在 类 内存中呀

辅助工具:
MachOView: 查看编译内存中是否存在类方法

image.png

事实证明:类方法确实存在
好了 不兜圈子了,那我们如何找到呢😺

  • 骚操作猜想:既然我们的类方法不存在与该 的内存中,那么我们是否可以去该类的元类中去找找呢,话不多说,动手,
    image.png

step1:取到LGPerson 的 元类
.....
step7:类方法已经获取到

总结:对象方法存在类里面,类方法存在元类里面

猜想成功、大功告成✿✿ヽ(°▽°)ノ✿


课外扩展:

指针平移:

    int c[4] = {1,2,3,4};
    int* x = c ;
    for (int i = 0; i < 4 ; i++) {
        int d = c[i];
        //等价于
        int b = *(x+i);
        NSLog(@"%d",d);
        NSLog(@"%d",b);
    }

输出语句一模一样,即验证了指针平移的操作!!!

相关文章

  • 二:类的内存结构分析

    上小节回顾:*上节课我们介绍实例化对象的内存分部,其中包含了isa指针内存和其属性,其中isa指针中存储了非常重要...

  • iOS-OC底层04:类结构分析

    类结构分析 通过lldb来分析类结构 查看objc2的内存情况 类对象只有一份,isa对象-> 类(LGPerso...

  • iOS 类的结构分析(下)

    在上一篇 iOS 类的结构分析(上) 分析了类的结构、isa 的走位以及类的内存分布(属性列表&实例方法列表),这...

  • 类的结构分析

    类分析初探 基于isa结构分析 ,我们可以通过lldb获取对象的内存情况 创建一个Person类对象 查看类对象的...

  • iOS底层原理:类&类的结构分析

    在分析类的结构之前,我们需要先搞清楚类的内存分布情况。 类的内存分布 首先创建一个Person类: 通过上图中可以...

  • iOS源码解析—YYCache(YYMemoryCache)

    概述 上一篇主要讲解了YYCache的文件结构,分析了YYCache类的相关方法,本章主要分析内存缓存类YYMem...

  • iOS底层之类的结构分析

    从iOS底层之isa结构分析及关联类我们探究了类的实例对象的内存结构,对象指针的首地址存储了isa,也就是存储了类...

  • Swift复习四&五

    内存分析 结构体 类 值类型 引用类型 一: 汇编发展 二: 汇编语言种类 三: 常见指令 四: 寄存器 五: m...

  • Redis 源码分析(五) :ziplist

    Redis 源码分析(五) :ziplist一、前言二、存储结构zlentry的内存布局zlentry数据结构三、...

  • 类的结构分析(二)

    由类的结构分析 中属性列表和方法列表分析可得出property_list中只有属性,没有成员变量,entsize_...

网友评论

    本文标题:二:类的内存结构分析

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