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

Ruby_Infant · 发布于 2017年04月17日 · 最后由 Ruby_Infant 回复于 2017年04月17日 · 588 次阅读
D7b415

最近开始学习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 源代码学习:对象模型

共收到 2 条回复
1

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

D7b415
1Rei 回复

好的,我下次注意!

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