Ruby GC実装の歴史/Ruby2.1のGCを読む
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Ruby GC実装の歴史を読む]]
#contents
*はじめに [#l3de614b]
Ruby 2.1ではRGenGC(Restricted Generation GC)が導入されま...
*RGenGCのパラメータ [#wbd01e59]
gc.cを上から見ていくとまずRGenGCのパラメータをdefineして...
#code(C){{
#define RGENGC_DEBUG 0
#define RGENGC_CHECK_MODE 0
#define RGENGC_PROFILE 0
#define RGENGC_THREEGEN 0
#define RGENGC_ESTIMATE_OLDMALLOC 1
}}
パラメータのうち上3つはデバッグ・プロファイリング用、下2...
*rb_newobj() [#g3773ce1]
いつもながらにrb_newobj()から見ていきます。下請けのnewobj...
#code(C){{
obj = heap_get_freeobj(objspace, heap_eden);
}}
2.1以降、heapは複数持たれるようになったようです。heap_ede...
で、heap_get_freeobj()。
#code(C){{
static inline VALUE
heap_get_freeobj(rb_objspace_t *objspace, rb_heap_t *heap)
{
RVALUE *p = heap->freelist;
while (1) {
if (p) {
heap->freelist = p->as.free.next;
return (VALUE)p;
}
else {
p = heap_get_freeobj_from_next_freepage(objsp...
}
}
}
}}
2.0でslotごとにfreelistを管理するようになったはずですが見...
#code(C){{
static RVALUE *
heap_get_freeobj_from_next_freepage(rb_objspace_t *objspa...
{
struct heap_page *page;
RVALUE *p;
page = heap->free_pages;
while (page == NULL) {
page = heap_prepare_freepage(objspace, heap);
}
heap->free_pages = page->free_next;
heap->using_page = page;
p = page->freelist;
page->freelist = NULL;
return p;
}
}}
heap_pageは2.0までのheaps_slotと同じようなものです。free...
さらに進む。ちょっと長いので一部端折ります。
#code(C){{
static struct heap_page *
heap_prepare_freepage(rb_objspace_t *objspace, rb_heap_t ...
{
if (!heap_ready_to_gc(objspace, heap)) return heap->f...
during_gc++;
if ((is_lazy_sweeping(heap) && gc_heap_lazy_sweep(obj...
goto ok;
}
if (garbage_collect_body(objspace, 0, 0, GPR_FLAG_NEW...
err:
during_gc = 0;
rb_memerror();
}
ok:
during_gc = 0;
return heap->free_pages;
}
}}
*garbage_collect_body() [#uf90f0ca]
garbage_collect_body()に進む。プロファイル系のコードとか...
#code(C){{
static int
garbage_collect_body(rb_objspace_t *objspace, int full_ma...
{
if (full_mark) {
reason |= GPR_FLAG_MAJOR_BY_NOFREE;
}
if (objspace->rgengc.need_major_gc) {
reason |= objspace->rgengc.need_major_gc;
objspace->rgengc.need_major_gc = GPR_FLAG_NONE;
}
if (objspace->rgengc.remembered_shady_object_count > ...
reason |= GPR_FLAG_MAJOR_BY_SHADY;
}
if (objspace->rgengc.old_object_count > objspace->rge...
reason |= GPR_FLAG_MAJOR_BY_OLDGEN;
}
if (immediate_sweep) reason |= GPR_FLAG_IMMEDIATE_SWE...
full_mark = (reason & GPR_FLAG_MAJOR_MASK) ? TRUE : F...
gc_marks(objspace, full_mark);
gc_sweep(objspace, immediate_sweep);
during_gc = 0;
return TRUE;
}
}}
RGenGCに関するパラメータが出てきました。見た感じ、以下の...
-need_major_gcに値が設定されているとき
-shadyオブジェクトがリミットを超えたとき
-oldオブジェクトがリミットを超えたとき
それぞれの条件に関する記述は今まで見てきた中にはまだ出て...
gc_marks()に進む。
#code(C){{
static void
gc_marks(rb_objspace_t *objspace, int full_mark)
{
struct mark_func_data_struct *prev_mark_func_data;
/* setup marking */
prev_mark_func_data = objspace->mark_func_data;
objspace->mark_func_data = 0;
if (full_mark == TRUE) { /* major/full GC */
objspace->rgengc.remembered_shady_object_count = 0;
objspace->rgengc.old_object_count = 0;
gc_marks_body(objspace, TRUE);
{
/* See the comment about RUBY_GC_HEAP_OLDOBJE...
const double r = gc_params.oldobject_limit_fa...
objspace->rgengc.remembered_shady_object_limi...
objspace->rgengc.old_object_limit = objspace-...
}
}
else { /* minor GC */
gc_marks_body(objspace, FALSE);
}
objspace->mark_func_data = prev_mark_func_data;
}
}}
とりあえずリミットに関する処理が出てきました。oldobject_l...
続いてgc_marks_body()。
#code(C){{
static void
gc_marks_body(rb_objspace_t *objspace, int full_mark)
{
objspace->rgengc.parent_object_is_old = FALSE;
objspace->rgengc.during_minor_gc = full_mark ? FALSE ...
if (objspace->rgengc.during_minor_gc) {
rgengc_rememberset_mark(objspace, heap_eden);
}
else {
rgengc_mark_and_rememberset_clear(objspace, heap_...
}
gc_mark_roots(objspace, full_mark, 0);
gc_mark_stacked_objects(objspace);
}
}}
major GCかminor GCかで処理が分かれています。まずはmajor G...
*major GCの場合 [#s8f19b36]
というわけでrgengc_mark_and_rememberset_clear()。
#code(C){{
static void
rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace...
{
struct heap_page *page = heap->pages;
while (page) {
memset(&page->mark_bits[0], 0, HEAP_BITMAP...
memset(&page->rememberset_bits[0], 0, HEAP_BITMAP...
page = page->next;
}
}
}}
mark_bitsは2.0から導入されたビットマップマーキングに関す...
gc_mark_roots()、gc_mark_stacked_objects()は毎度おなじみ...
#code(C){{
static void
gc_mark(rb_objspace_t *objspace, VALUE ptr)
{
if (!is_markable_object(objspace, ptr)) return;
if (LIKELY(objspace->mark_func_data == 0)) {
rgengc_check_relation(objspace, ptr);
if (!gc_mark_ptr(objspace, ptr)) return; /* alrea...
push_mark_stack(&objspace->mark_stack, ptr);
}
else {
objspace->mark_func_data->mark_func(ptr, objspace...
}
}
}}
2.0のころと比べると、rgengc_check_relation()が増えていま...
#code(C){{
static void
rgengc_check_relation(rb_objspace_t *objspace, VALUE obj)
{
if (objspace->rgengc.parent_object_is_old) {
if (!RVALUE_WB_PROTECTED(obj)) {
if (rgengc_remember(objspace, obj)) {
objspace->rgengc.remembered_shady_object_...
}
}
}
}
}}
親がoldかつ自身がライトバリア保護されていない場合、rememb...
覚えておくってどういうことなのかわからないのでgc_mark_chi...
#code(C){{
static void
gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
{
register RVALUE *obj = RANY(ptr);
goto marking; /* skip */
again:
if (LIKELY(objspace->mark_func_data == 0)) {
obj = RANY(ptr);
if (!is_markable_object(objspace, ptr)) return;
rgengc_check_relation(objspace, ptr);
if (!gc_mark_ptr(objspace, ptr)) return; /* alre...
}
else {
gc_mark(objspace, ptr);
return;
}
marking:
if (LIKELY(objspace->mark_func_data == 0)) {
/* minor/major common */
if (RVALUE_WB_PROTECTED(obj)) {
if (RVALUE_INFANT_P((VALUE)obj)) {
RVALUE_PROMOTE_INFANT((VALUE)obj);
/* infant -> old */
objspace->rgengc.old_object_count++;
objspace->rgengc.parent_object_is_old = T...
}
else {
objspace->rgengc.parent_object_is_old = T...
if (!objspace->rgengc.during_minor_gc) {
/* major/full GC */
objspace->rgengc.old_object_count++;
}
}
}
else {
objspace->rgengc.parent_object_is_old = FALSE;
}
}
(以下、従来通り)
}}
infantは幼児、つまり、最後にGCしてから生まれたオブジェク...
RVALUE_PROMOTE_INFANT()をデバッグコード省略して2世代GCに...
#code(C){{
static inline void
RVALUE_PROMOTE_INFANT(VALUE obj)
{
FL_SET2(obj, FL_PROMOTED);
MARK_IN_BITMAP(GET_HEAP_OLDGEN_BITS(obj), obj);
}
}}
*minor GCの場合 [#gb679a40]
さて、というわけでオブジェクトがoldに設定される個所は確認...
#code(C){{
static void
gc_marks_body(rb_objspace_t *objspace, int full_mark)
{
objspace->rgengc.parent_object_is_old = FALSE;
objspace->rgengc.during_minor_gc = full_mark ? FALSE ...
if (objspace->rgengc.during_minor_gc) {
rgengc_rememberset_mark(objspace, heap_eden);
}
else {
rgengc_mark_and_rememberset_clear(objspace, heap_...
}
gc_mark_roots(objspace, full_mark, 0);
gc_mark_stacked_objects(objspace);
}
}}
です。during_minor_gcがTRUE(full_markがFALSE)を見ると前...
2.0から、オブジェクトのマークとはビットマップ中のオブジェ...
もうビットが立っていたら改めてそれ以降(フィールド)のマ...
ところで、full_markがTRUEの場合はマークされてるかビットを...
つまり、一度マークされたオブジェクトは次にmajor GCが起こ...
さて、以上、終わり、とできれば話は楽なのですがこれだけだ...
戻ってきていただきありがとうございます。そう、謎のremembe...
*ライトバリア周り [#l74af530]
では残りの問題を片付けましょう。残っているのは、ライトバ...
-newなオブジェクトを参照したoldはrembersetに送られる
-RARRAY_PTRマクロを使われるなど追っかけきれない場合はshad...
それぞれ見ていきましょう。
**old→newしたらremebersetに送られる [#tfb54353]
オブジェクト間の参照関係ということで、Array#[]=を実装して...
#code(C){{
static VALUE
rb_ary_aset(int argc, VALUE *argv, VALUE ary)
{
long offset;
offset = NUM2LONG(argv[0]);
rb_ary_store(ary, offset, argv[1]);
return argv[1];
}
void
rb_ary_store(VALUE ary, long idx, VALUE val)
{
RARRAY_ASET(ary, idx, val);
}
}}
RARRAY_ASETはruby.hに書かれているマクロです。
#code(C){{
#define RARRAY_ASET(a, i, v) do { \
const VALUE _ary_ = (a); \
RB_OBJ_WRITE(_ary_, &RARRAY_CONST_PTR(_ary_)[i], (v))...
} while (0)
}}
RB_OBJ_WRITEマクロはファイル名と行番号を追加して同じくrub...
#code(C){{
static inline VALUE
rb_obj_write(VALUE a, VALUE *slot, VALUE b, RB_UNUSED_VAR...
{
*slot = b;
rb_obj_written(a, Qundef /* ignore `oldv' now */, b, ...
return a;
}
}}
rb_obj_written()もruby.hに書かれています。
#code(C){{
static inline VALUE
rb_obj_written(VALUE a, RB_UNUSED_VAR(VALUE oldv), VALUE ...
{
/* `a' should be an RVALUE object */
if (FL_TEST_RAW((a), FL_PROMOTED) && !SPECIAL_CONST_P...
rb_gc_writebarrier(a, b);
}
return a;
}
}}
a、フィールドを変更しようとしたオブジェクトがoldだったらr...
#code(C){{
void
rb_gc_writebarrier(VALUE a, VALUE b)
{
if (!RVALUE_OLD_P(b) && RVALUE_OLD_BITMAP_P(a)) {
rb_objspace_t *objspace = &rb_objspace;
if (!rgengc_remembered(objspace, a)) {
int type = BUILTIN_TYPE(a);
/* TODO: 2 << 16 is just a magic number. */
if ((type == T_ARRAY && RARRAY_LEN(a) >= 2 <<...
(type == T_HASH && RHASH_SIZE(a) >= 2 <<...
if (!rgengc_remembered(objspace, b)) {
rgengc_remember(objspace, b);
}
}
else {
rgengc_remember(objspace, a);
}
}
}
}
}}
仕様通り、newなオブジェクトを参照したoldがremembersetに送...
**管理しきれない場合はライトバリアを外す [#idbe3422]
最後にRARRAY_PTRマクロを見てみましょう。再びruby.hです。
#code(C){{
#define RARRAY_PTR(a) ((VALUE *)RARRAY_CONST_PTR(RGENGC_W...
}}
unprotectされています。もう少し追いかけてみましょう。
#code(C){{
#define OBJ_WB_UNPROTECT(x) (x, __FILE__, __LINE__)
static inline VALUE
rb_obj_wb_unprotect(VALUE x, RB_UNUSED_VAR(const char *fi...
{
/* `x' should be an RVALUE object */
if (FL_TEST_RAW((x), FL_WB_PROTECTED)) {
if (FL_TEST_RAW((x), FL_PROMOTED)) {
rb_gc_writebarrier_unprotect_promoted(x);
}
RBASIC(x)->flags &= ~FL_WB_PROTECTED;
}
return x;
}
}}
ここからgc.c。
#code(C){{
void
rb_gc_writebarrier_unprotect_promoted(VALUE obj)
{
rb_objspace_t *objspace = &rb_objspace;
if (RVALUE_OLD_P(obj)) {
RVALUE_DEMOTE_FROM_OLD(obj);
rgengc_remember(objspace, obj);
objspace->rgengc.remembered_shady_object_count++;
}
}
}}
というわけでoldオブジェクトからshadyオブジェクトになりま...
*で、結局何がRestrictedなのか [#a99202a8]
-本当ならold→newの参照をする可能性のあるところにはすべて...
-が、そのためには過去の拡張ライブラリを全ビルドしないとい...
-だったら、ライトバリアされてなくても動けるようにしてライ...
というのが世代別GCを入れたけど、効果は限定されてますよ〜...
*おわりに [#t26f7c36]
さて、2.1のGC(RGenGC)を見てきました。どういうものかは先...
RGenGCを読むにあたって1.9.3、2.0と順に読んできましたが無...
終了行:
[[Ruby GC実装の歴史を読む]]
#contents
*はじめに [#l3de614b]
Ruby 2.1ではRGenGC(Restricted Generation GC)が導入されま...
*RGenGCのパラメータ [#wbd01e59]
gc.cを上から見ていくとまずRGenGCのパラメータをdefineして...
#code(C){{
#define RGENGC_DEBUG 0
#define RGENGC_CHECK_MODE 0
#define RGENGC_PROFILE 0
#define RGENGC_THREEGEN 0
#define RGENGC_ESTIMATE_OLDMALLOC 1
}}
パラメータのうち上3つはデバッグ・プロファイリング用、下2...
*rb_newobj() [#g3773ce1]
いつもながらにrb_newobj()から見ていきます。下請けのnewobj...
#code(C){{
obj = heap_get_freeobj(objspace, heap_eden);
}}
2.1以降、heapは複数持たれるようになったようです。heap_ede...
で、heap_get_freeobj()。
#code(C){{
static inline VALUE
heap_get_freeobj(rb_objspace_t *objspace, rb_heap_t *heap)
{
RVALUE *p = heap->freelist;
while (1) {
if (p) {
heap->freelist = p->as.free.next;
return (VALUE)p;
}
else {
p = heap_get_freeobj_from_next_freepage(objsp...
}
}
}
}}
2.0でslotごとにfreelistを管理するようになったはずですが見...
#code(C){{
static RVALUE *
heap_get_freeobj_from_next_freepage(rb_objspace_t *objspa...
{
struct heap_page *page;
RVALUE *p;
page = heap->free_pages;
while (page == NULL) {
page = heap_prepare_freepage(objspace, heap);
}
heap->free_pages = page->free_next;
heap->using_page = page;
p = page->freelist;
page->freelist = NULL;
return p;
}
}}
heap_pageは2.0までのheaps_slotと同じようなものです。free...
さらに進む。ちょっと長いので一部端折ります。
#code(C){{
static struct heap_page *
heap_prepare_freepage(rb_objspace_t *objspace, rb_heap_t ...
{
if (!heap_ready_to_gc(objspace, heap)) return heap->f...
during_gc++;
if ((is_lazy_sweeping(heap) && gc_heap_lazy_sweep(obj...
goto ok;
}
if (garbage_collect_body(objspace, 0, 0, GPR_FLAG_NEW...
err:
during_gc = 0;
rb_memerror();
}
ok:
during_gc = 0;
return heap->free_pages;
}
}}
*garbage_collect_body() [#uf90f0ca]
garbage_collect_body()に進む。プロファイル系のコードとか...
#code(C){{
static int
garbage_collect_body(rb_objspace_t *objspace, int full_ma...
{
if (full_mark) {
reason |= GPR_FLAG_MAJOR_BY_NOFREE;
}
if (objspace->rgengc.need_major_gc) {
reason |= objspace->rgengc.need_major_gc;
objspace->rgengc.need_major_gc = GPR_FLAG_NONE;
}
if (objspace->rgengc.remembered_shady_object_count > ...
reason |= GPR_FLAG_MAJOR_BY_SHADY;
}
if (objspace->rgengc.old_object_count > objspace->rge...
reason |= GPR_FLAG_MAJOR_BY_OLDGEN;
}
if (immediate_sweep) reason |= GPR_FLAG_IMMEDIATE_SWE...
full_mark = (reason & GPR_FLAG_MAJOR_MASK) ? TRUE : F...
gc_marks(objspace, full_mark);
gc_sweep(objspace, immediate_sweep);
during_gc = 0;
return TRUE;
}
}}
RGenGCに関するパラメータが出てきました。見た感じ、以下の...
-need_major_gcに値が設定されているとき
-shadyオブジェクトがリミットを超えたとき
-oldオブジェクトがリミットを超えたとき
それぞれの条件に関する記述は今まで見てきた中にはまだ出て...
gc_marks()に進む。
#code(C){{
static void
gc_marks(rb_objspace_t *objspace, int full_mark)
{
struct mark_func_data_struct *prev_mark_func_data;
/* setup marking */
prev_mark_func_data = objspace->mark_func_data;
objspace->mark_func_data = 0;
if (full_mark == TRUE) { /* major/full GC */
objspace->rgengc.remembered_shady_object_count = 0;
objspace->rgengc.old_object_count = 0;
gc_marks_body(objspace, TRUE);
{
/* See the comment about RUBY_GC_HEAP_OLDOBJE...
const double r = gc_params.oldobject_limit_fa...
objspace->rgengc.remembered_shady_object_limi...
objspace->rgengc.old_object_limit = objspace-...
}
}
else { /* minor GC */
gc_marks_body(objspace, FALSE);
}
objspace->mark_func_data = prev_mark_func_data;
}
}}
とりあえずリミットに関する処理が出てきました。oldobject_l...
続いてgc_marks_body()。
#code(C){{
static void
gc_marks_body(rb_objspace_t *objspace, int full_mark)
{
objspace->rgengc.parent_object_is_old = FALSE;
objspace->rgengc.during_minor_gc = full_mark ? FALSE ...
if (objspace->rgengc.during_minor_gc) {
rgengc_rememberset_mark(objspace, heap_eden);
}
else {
rgengc_mark_and_rememberset_clear(objspace, heap_...
}
gc_mark_roots(objspace, full_mark, 0);
gc_mark_stacked_objects(objspace);
}
}}
major GCかminor GCかで処理が分かれています。まずはmajor G...
*major GCの場合 [#s8f19b36]
というわけでrgengc_mark_and_rememberset_clear()。
#code(C){{
static void
rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace...
{
struct heap_page *page = heap->pages;
while (page) {
memset(&page->mark_bits[0], 0, HEAP_BITMAP...
memset(&page->rememberset_bits[0], 0, HEAP_BITMAP...
page = page->next;
}
}
}}
mark_bitsは2.0から導入されたビットマップマーキングに関す...
gc_mark_roots()、gc_mark_stacked_objects()は毎度おなじみ...
#code(C){{
static void
gc_mark(rb_objspace_t *objspace, VALUE ptr)
{
if (!is_markable_object(objspace, ptr)) return;
if (LIKELY(objspace->mark_func_data == 0)) {
rgengc_check_relation(objspace, ptr);
if (!gc_mark_ptr(objspace, ptr)) return; /* alrea...
push_mark_stack(&objspace->mark_stack, ptr);
}
else {
objspace->mark_func_data->mark_func(ptr, objspace...
}
}
}}
2.0のころと比べると、rgengc_check_relation()が増えていま...
#code(C){{
static void
rgengc_check_relation(rb_objspace_t *objspace, VALUE obj)
{
if (objspace->rgengc.parent_object_is_old) {
if (!RVALUE_WB_PROTECTED(obj)) {
if (rgengc_remember(objspace, obj)) {
objspace->rgengc.remembered_shady_object_...
}
}
}
}
}}
親がoldかつ自身がライトバリア保護されていない場合、rememb...
覚えておくってどういうことなのかわからないのでgc_mark_chi...
#code(C){{
static void
gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
{
register RVALUE *obj = RANY(ptr);
goto marking; /* skip */
again:
if (LIKELY(objspace->mark_func_data == 0)) {
obj = RANY(ptr);
if (!is_markable_object(objspace, ptr)) return;
rgengc_check_relation(objspace, ptr);
if (!gc_mark_ptr(objspace, ptr)) return; /* alre...
}
else {
gc_mark(objspace, ptr);
return;
}
marking:
if (LIKELY(objspace->mark_func_data == 0)) {
/* minor/major common */
if (RVALUE_WB_PROTECTED(obj)) {
if (RVALUE_INFANT_P((VALUE)obj)) {
RVALUE_PROMOTE_INFANT((VALUE)obj);
/* infant -> old */
objspace->rgengc.old_object_count++;
objspace->rgengc.parent_object_is_old = T...
}
else {
objspace->rgengc.parent_object_is_old = T...
if (!objspace->rgengc.during_minor_gc) {
/* major/full GC */
objspace->rgengc.old_object_count++;
}
}
}
else {
objspace->rgengc.parent_object_is_old = FALSE;
}
}
(以下、従来通り)
}}
infantは幼児、つまり、最後にGCしてから生まれたオブジェク...
RVALUE_PROMOTE_INFANT()をデバッグコード省略して2世代GCに...
#code(C){{
static inline void
RVALUE_PROMOTE_INFANT(VALUE obj)
{
FL_SET2(obj, FL_PROMOTED);
MARK_IN_BITMAP(GET_HEAP_OLDGEN_BITS(obj), obj);
}
}}
*minor GCの場合 [#gb679a40]
さて、というわけでオブジェクトがoldに設定される個所は確認...
#code(C){{
static void
gc_marks_body(rb_objspace_t *objspace, int full_mark)
{
objspace->rgengc.parent_object_is_old = FALSE;
objspace->rgengc.during_minor_gc = full_mark ? FALSE ...
if (objspace->rgengc.during_minor_gc) {
rgengc_rememberset_mark(objspace, heap_eden);
}
else {
rgengc_mark_and_rememberset_clear(objspace, heap_...
}
gc_mark_roots(objspace, full_mark, 0);
gc_mark_stacked_objects(objspace);
}
}}
です。during_minor_gcがTRUE(full_markがFALSE)を見ると前...
2.0から、オブジェクトのマークとはビットマップ中のオブジェ...
もうビットが立っていたら改めてそれ以降(フィールド)のマ...
ところで、full_markがTRUEの場合はマークされてるかビットを...
つまり、一度マークされたオブジェクトは次にmajor GCが起こ...
さて、以上、終わり、とできれば話は楽なのですがこれだけだ...
戻ってきていただきありがとうございます。そう、謎のremembe...
*ライトバリア周り [#l74af530]
では残りの問題を片付けましょう。残っているのは、ライトバ...
-newなオブジェクトを参照したoldはrembersetに送られる
-RARRAY_PTRマクロを使われるなど追っかけきれない場合はshad...
それぞれ見ていきましょう。
**old→newしたらremebersetに送られる [#tfb54353]
オブジェクト間の参照関係ということで、Array#[]=を実装して...
#code(C){{
static VALUE
rb_ary_aset(int argc, VALUE *argv, VALUE ary)
{
long offset;
offset = NUM2LONG(argv[0]);
rb_ary_store(ary, offset, argv[1]);
return argv[1];
}
void
rb_ary_store(VALUE ary, long idx, VALUE val)
{
RARRAY_ASET(ary, idx, val);
}
}}
RARRAY_ASETはruby.hに書かれているマクロです。
#code(C){{
#define RARRAY_ASET(a, i, v) do { \
const VALUE _ary_ = (a); \
RB_OBJ_WRITE(_ary_, &RARRAY_CONST_PTR(_ary_)[i], (v))...
} while (0)
}}
RB_OBJ_WRITEマクロはファイル名と行番号を追加して同じくrub...
#code(C){{
static inline VALUE
rb_obj_write(VALUE a, VALUE *slot, VALUE b, RB_UNUSED_VAR...
{
*slot = b;
rb_obj_written(a, Qundef /* ignore `oldv' now */, b, ...
return a;
}
}}
rb_obj_written()もruby.hに書かれています。
#code(C){{
static inline VALUE
rb_obj_written(VALUE a, RB_UNUSED_VAR(VALUE oldv), VALUE ...
{
/* `a' should be an RVALUE object */
if (FL_TEST_RAW((a), FL_PROMOTED) && !SPECIAL_CONST_P...
rb_gc_writebarrier(a, b);
}
return a;
}
}}
a、フィールドを変更しようとしたオブジェクトがoldだったらr...
#code(C){{
void
rb_gc_writebarrier(VALUE a, VALUE b)
{
if (!RVALUE_OLD_P(b) && RVALUE_OLD_BITMAP_P(a)) {
rb_objspace_t *objspace = &rb_objspace;
if (!rgengc_remembered(objspace, a)) {
int type = BUILTIN_TYPE(a);
/* TODO: 2 << 16 is just a magic number. */
if ((type == T_ARRAY && RARRAY_LEN(a) >= 2 <<...
(type == T_HASH && RHASH_SIZE(a) >= 2 <<...
if (!rgengc_remembered(objspace, b)) {
rgengc_remember(objspace, b);
}
}
else {
rgengc_remember(objspace, a);
}
}
}
}
}}
仕様通り、newなオブジェクトを参照したoldがremembersetに送...
**管理しきれない場合はライトバリアを外す [#idbe3422]
最後にRARRAY_PTRマクロを見てみましょう。再びruby.hです。
#code(C){{
#define RARRAY_PTR(a) ((VALUE *)RARRAY_CONST_PTR(RGENGC_W...
}}
unprotectされています。もう少し追いかけてみましょう。
#code(C){{
#define OBJ_WB_UNPROTECT(x) (x, __FILE__, __LINE__)
static inline VALUE
rb_obj_wb_unprotect(VALUE x, RB_UNUSED_VAR(const char *fi...
{
/* `x' should be an RVALUE object */
if (FL_TEST_RAW((x), FL_WB_PROTECTED)) {
if (FL_TEST_RAW((x), FL_PROMOTED)) {
rb_gc_writebarrier_unprotect_promoted(x);
}
RBASIC(x)->flags &= ~FL_WB_PROTECTED;
}
return x;
}
}}
ここからgc.c。
#code(C){{
void
rb_gc_writebarrier_unprotect_promoted(VALUE obj)
{
rb_objspace_t *objspace = &rb_objspace;
if (RVALUE_OLD_P(obj)) {
RVALUE_DEMOTE_FROM_OLD(obj);
rgengc_remember(objspace, obj);
objspace->rgengc.remembered_shady_object_count++;
}
}
}}
というわけでoldオブジェクトからshadyオブジェクトになりま...
*で、結局何がRestrictedなのか [#a99202a8]
-本当ならold→newの参照をする可能性のあるところにはすべて...
-が、そのためには過去の拡張ライブラリを全ビルドしないとい...
-だったら、ライトバリアされてなくても動けるようにしてライ...
というのが世代別GCを入れたけど、効果は限定されてますよ〜...
*おわりに [#t26f7c36]
さて、2.1のGC(RGenGC)を見てきました。どういうものかは先...
RGenGCを読むにあたって1.9.3、2.0と順に読んできましたが無...
ページ名: