GOGATSU やぶ

【技術学習log】【Ruby】【C言語】Rubyオブジェクトのメモリ管理

 Rubyの場合、オブジェクトのサイズは基本40バイトで構成されているという情報をみた。
 とても気になったので、Rubyオブジェクトのメモリ管理から、Rubyオブジェクトの構造まで調べてみた。

 参考記事1:
 第2章 オブジェクト

 参考記事2:
 第5章 ガ−ベージコレクション

 参考記事3:  Ruby におけるメモリの話 - Qiita

 参考記事4:
 レアでアレなGCの話

 参考記事5:
メモリとスタックとヒープとプログラミング言語 | κeenのHappy Hacκing Blog

1. RubyのHeap領域

 オブジェクトを生成したときに保存する領域を調べてみる。

参考記事4 「RubyGCの仕組み」:

 ...ここで差しているヒープ領域とはCのヒープ領域では無く、Ruby が使用するヒープ領域のことです。

 Heap領域は好きなタイミングでメモリを確保したり、解放したりできるメモリ空間のこと。
 プログラム実行時に、OSさんが一定量のHeap領域を確保してくれる。
 RubyにはRubyオブジェクトを使うためのHeap領域というものがあるらしい。

---RubyのHeap領域について---

参考記事5 「Ruby」:

 データ領域にはHeapにmallocで確保した領域にヒープを確保し、その上にメモリ管理システム(GC)を構築して管理しています。

 malloc関数は、C言語の動的メモリ確保メソッド(好きなタイミングでメモリが欲しい時につかうもの)。

 なので、OSさんがくれたHeap領域から、malloc関数でメモリを確保し、これをRuby用Heap領域として使っている。

f:id:ybsatsuki:20211121131435p:plain

 この中で、Rubyオブジェクトはどう確保されているのかみてみる。

参考記事4 「RubyGCの仕組み」:

 RVALUE という構造体の配列の配列という形で、Ruby のヒープ領域は確保されています。

参考記事3 :

・HeapはSlot(とPage)からなる
Rubyオブジェクト(RVALUE)が生成されるとSlotに配置される
・各Slotのサイズは40Byte
・HeapはPageに分割されて、各Page毎にSlotがある

 上記をもとに、イメージ図を作成してみた。
 各slotに40バイトのサイズを確保し、RVALUE構造体のポインタを格納している。
 もしオブジェクトが40byteを超えるような場合は、OSさんに別途メモリを確保してもらう。

f:id:ybsatsuki:20211121121043p:plain

2. RVALUE構造体

 RVALUE構造体は、各種オブジェクト構造体(RStringやRArrayなど)を共用体として持っている。

参考記事2 「struct RVALUE」:

コードの一部を編集(コメント追加など)。

//structで構造体宣言
typedef struct RVALUE {

    //unionで共用体宣言(unionの中に、色々なstruct)
    union {
      struct {
          VALUE flags;        /* 使われていない時はゼロ */
          struct RVALUE *next;
      } free;
      struct RBasic  basic; 
      struct RObject object;
      struct RString string;
      struct RArray  array;

      /* ~snip~ */

    } as;
} RVALUE;

---共用体について---
 C言語で使われるデータ型の1つ。
 共用体に定義された型は、同じメモリを共有できる。

 RVALUEで、各構造体を共用体として持つ場合と、仮に持たなかった場合のイメージ図。

f:id:ybsatsuki:20211121150856p:plain

 共用体にすると、実際に使うまで1slotに複数の構造体を置いておける。
 (これが仮に共用体でない場合は、いろんな場所に複数の構造体を置くので、メモリの消費量は多い。)

 ※共用体では同じメモリを共有しているので、共用体に定義されている型は複数同時に使うことはできない。
 たとえば、1pageめ3slotに新しいオブジェクトを作る際、RStringとRArray両方を同時に生成し、使うことはできない。
(そんなことができるのか、起こるのかはちょっとわからない。)

f:id:ybsatsuki:20211121133016p:plain

3. RVALUEの各種オブジェクト構造体

参考記事1 「VALUEとオブジェクト構造体」:

/* 一般のオブジェクトのための構造体 */
struct RObject {
  struct RBasic basic;
  struct st_table *iv_tbl;
};

/* 文字列(Stringのインスタンス)のための構造体 */
struct RString {
  struct RBasic basic;
  long len;
  char *ptr;
  union {
    long capa;
    VALUE shared;
  } aux;
};

/* 配列(Arrayのインスタンス)のための構造体 */
struct RArray {
  struct RBasic basic;
  long len;
  union {
    long capa;
    VALUE shared;
  } aux;
  VALUE *ptr;
};

 各種オブジェクト構造体の中身をみると、RBasicという構造体が入っている。
 RBasicには、flagsとklassという情報が入っている。

参考記事1 「VALUEとオブジェクト構造体」:

struct RBasic {
    unsigned long flags;
    VALUE klass;
};

 RBasicのflagsには、構造体の型を記憶しておく「構造体型(6bit)」、ガベージコレクションをするためのマーク「FL_MARK(1bit)」などが入っている。

f:id:ybsatsuki:20211121125836p:plain
第2章 オブジェクト - Minero Aoki -

次回以降

 Rubyオブジェクトの中に、ガベージコレクションのために必要なフラグがあるのを知って、GCの仕組みが気になった。
 今のところ、「なにかフラグつけて管理してる。フラグの付け方、再帰検索の方法は色々ある」というイメージ。
 Rubyガベージコレクション深掘りして、JavaScriptガベージコレクションも調べてみて、共通点や違いを考えるのも楽しそう。