Аудитория
Руби освобождает страницы
gc_sweep_finish(rb_objspace_t *objspace)
heap_pages_free_unused_pages(rb_objspace_t *objspace)
heap_page_free(rb_objspace_t *objspace, struct heap_page *page) { free(page); }
О чем поговорим
• как работает GC
• как устроен GC
• планы ruby team
gc.c
9381 lines and counting
На первый взгляд
Через пару дней
Чем занимается• создает объекты
• выделяет память под них
• освобождает
• собирает статистику
• проверяет консистентность объектов
• …
• собирает мусор
Структура
RVALUE
GC::INTERNAL_CONSTANTS[:RVALUE_SIZE] # => 40
* sizeof(RVALUE) is
* 20 if 32-bit, double is 4-byte aligned
* 24 if 32-bit, double is 8-byte aligned
* 40 if 64-bit
heap_page
GC::INTERNAL_CONSTANTS[:HEAP_OBJ_LIMIT] # => 408
HEAP_PAGE_OBJ_LIMIT = ((HEAP_PAGE_SIZE - sizeof(struct heap_page_header)) / sizeof(struct RVALUE))
RVALUEtypedef struct RVALUE { union { struct {
VALUE flags; /* always 0 for freed obj */ struct RVALUE *next; } free; struct RBasic basic; struct RObject object; struct RClass klass; struct RString string; ... struct RComplex complex; ... } as; } RVALUE;
RStringstruct RString { struct RBasic basic; union {
struct { long len; char *ptr; union {
long capa; VALUE shared;
} aux; } heap; char ary[RSTRING_EMBED_LEN_MAX + 1];
} as; };
Развитие
• early - Mark & Sweep
• 1.9.3 - Lazy Sweep
• 2.0 - CoW friendly
• 2.1 - Mark major / minor
• 2.2 - Inc major Mark, symbols
Mark & Sweep
Mark & Sweep
Mark & SweepObjectSpace.reachable_objects_from_root.keys
[
[0] "vm",
[1] "machine_context",
[2] "global_list",
[3] "end_proc",
[4] "global_tbl"
]
Mark & Sweep
Mark & Sweep
Mark & Sweep
> a = 'a' * 1024 * 1024 * 500
> a = nil; 4.times { GC.start }
Mark & Sweep
Markgc_mark_roots(rb_objspace_t *objspace, const char **categoryp) { rb_thread_t *th = GET_THREAD(); rb_vm_mark(th->vm); mark_tbl(objspace, finalizer_table); mark_current_machine_context(objspace, th); rb_gc_mark_encodings();
/* mark protected global variables */ rb_gc_mark_maybe(*list->varptr);
rb_mark_end_proc(); rb_gc_mark_global_tbl(); }
Sweep
gc_sweep(rb_objspace_t *objspace) { if (immediate_sweep) { gc_sweep_start(objspace); gc_sweep_rest(objspace); } else { }
gc_heap_prepare_minimum_pages(objspace, heap_eden); }
Sweepgc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap) { while (sweep_page) { heap->sweep_pages = next = sweep_page->next; gc_page_sweep(objspace, heap, sweep_page);
heap_unlink_page(objspace, heap, sweep_page); heap_add_page(objspace, heap_tomb, sweep_page);
sweep_page = next; }
if (heap->sweep_pages == NULL) { gc_sweep_finish(objspace); }
return heap->free_pages != NULL; }
Lazy Sweep
Lazy Sweep
gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *heap)
Copy on Write (CoW)
heap_pagestruct heap_page {
struct heap_page *prev; short total_slots; short free_slots; short final_slots; struct heap_page *free_next; struct heap_page *next;
/* the following three bitmaps are cleared at the beginning of full GC */ bits_t mark_bits[HEAP_PAGE_BITMAP_LIMIT]; };
RGenGC
Major
Minor
Minor
Minor
4.times { GC.start }
if (objspace->last_major_gc > 3 /* magic number */) { gc_report(1, objspace, "gc_marks_finish: next is full GC!!)\n");
objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_NOFREE; }
Major через каждые 3 Minor цикла
RIncGC только для Major Mark
RIncGC Major Mark
RIncGC Major Mark
objspace->rincgc.step_slots = (objspace->marked_slots * 2) / ((objspace->rincgc.pooled_slots / HEAP_PAGE_OBJ_LIMIT) + 1);
RIncGC Major Mark
RIncGC Major Mark
heap_prepare(rb_objspace_t *objspace, rb_heap_t *heap)
RGenGC RIncGC
Restricted
Много слайдов про remember set
Много слайдов про write unprotected objects
Немного слайдов про write protected objects
Можно найти
• http://www.atdot.net/~ko1/activities/2015_rubyconfph_pub.pdf
• http://www.atdot.net/fp_store/f.p61can/file.data-incremental-gc.pdf
Дополнительно
• http://tmm1.net/ruby21-rgengc/
• https://ruby-hacking-guide.github.io/gc.html
• Ruby Under a Microscope - Pat Shaughnessy
• http://engineering.heroku.com/blogs/2015-02-04-incremental-gc
Дальнейшее развитие GC
ссылочка
https://esa-pages.io/p/sharing/2933/posts/5/2075ee3ce5a11a81cd00.html
Оптимизация Sweep
Спасибо
achempion