Ruby Ruby 学习笔记--对象模型

Ruby_Infant · 2017年04月17日 · 最后由 Ruby_Infant 回复于 2017年04月17日 · 2338 次阅读

最近开始学习 Ruby,现在整理一下自己学习的笔记,针对的 Ruby 是 MRI 版。其中难免有错误之处,还望大家批评指正。

自定义类对象模型

在源代码中可以看到 Ruby 使用 RObject 结构体来存储自定义类对象以及 Ruby 内部创建的少数自定义类,代码如下:

struct RBasic {
    VALUE flags;
    const VALUE klass;
}

#define ROBJECT_EMBED_LEN_MAX 3
struct RObject {
    struct RBasic basic;
    union {
    struct {
        long numiv; 
        VALUE *ivptr;
            struct st_table *iv_index_tbl; 
    } heap;
    VALUE ary[ROBJECT_EMBED_LEN_MAX];
    } as;
};

其中各部分的含义如下:
numiv: 实例变量的数目;
*ivptr: 实例变量值数组的指针,这里只保存值;
*iv_index_tbl: 指向一个散列表,该散列表是实例变量名及其在 ivptr 数组中位置的映射,这只是一个缓存,真实的散列是在对象对应的类的 RClass 结构体中的。
ary: 从代码中可以看出,ary 和上述三个变量使用同一块内存空间,它被用来保存实例变量。如果属性个数小于 ROBJECT_EMBED_LEN_MAX 属性值将直接存储在 ary 数组内,如果变量的大小合适,就会被全部保存,这样就不需要为了保存实例变量的值的数组而调用 malloc 来分配额外的内存;否则属性值和索引都存储在 heap 结构体中。

用一个图来表示如下图所示 (假设 ROBJECT_EMBED_LEN_MAX=1):

当我们使用 obj = ClassName.new 来创建一个对象的时候,obj 中会存储属于自己的实例变量的信息,同一个类的不同对象可能拥有不同个数的实例变量。同时 obj 的 klass 会指向自己的类。也就是说:

每个 Ruby 对象都是类指针和实例变量数组的组合。

基本类型对象模型

在 Ruby 中一切皆对象,基本的数据类型也是一样的。Ruby 使用了别的结构体来保存每个基本数据类型的值。如使用 RString 结构体保存字符串的值,使用 RArray 结构体保存数组等。但是,这些不同的结构体中都包含同样的 RBasic 结构体。如下图所示的是 RString 的简化版:


在 RString、RArray、RStruct 和 RBignum 结构体中同样使用了 ary 数组来优化内存。
此外,为了优化性能,Ruby 中保存小值整数、符号和其他一些简单立即值时没有使用任何结构体,只是将值放在 VALUE 中。在源码中,VALUE 的定义如下:

typedef unsigned long VALUE;

VALUE 可以看作是 long 类型的一个别名。在这里,Ruby 将其分为两部分:值和标志位。

在这里 VALUE 不在是指针,它们就是值本身。前几个比特存储值,后边的就是标志位。全部小值整数都有 FIXNUM_FLAG 位标记。

一旦 FIXNUM_FLAG 被设置,Ruby 就知道这个 VALUE 是一个小值整数,而不是指向结构体的指针。
在 Ruby 中,使用这种方式实现的类型还有 Symbol,true,false,nil 和 undef。从中可以看出为什么字符占用的资源比符号要多。

参考:
《Ruby 原理剖析》
xingpingz Ruby 2.X 源代码学习:对象模型

建议写在博客然后在这里贴介绍和目录,而不是一篇发一个贴。

Rei 回复

好的,我下次注意!

Ruby_Infant 关闭了讨论。 04月17日 21:15
需要 登录 后方可回复, 如果你还没有账号请 注册新账号