gc.c: replace gcnext gray linked list with fixed-size gray stack

remove per-object gcnext pointer from MRB_OBJECT_HEADER, saving one
word (8 bytes on 64-bit) per object slot. the gray list for tri-color
marking is replaced by a fixed-size stack (MRB_GRAY_STACK_SIZE=1024)
in mrb_gc. when the stack overflows, a linear heap rescan recovers
gray objects.

object slot size: 48 -> 40 bytes (16.7% reduction on 64-bit).
benchmarks show up to 12% RSS reduction on object-heavy workloads
with neutral performance impact.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-02-12 13:38:21 +09:00
parent 5d3aab8b22
commit 31fea1709f
8 changed files with 75 additions and 37 deletions
+7 -2
View File
@@ -28,6 +28,10 @@ MRB_API void mrb_free_context(struct mrb_state *mrb, struct mrb_context *c);
#define MRB_GC_ARENA_SIZE 100
#endif
#ifndef MRB_GRAY_STACK_SIZE
#define MRB_GRAY_STACK_SIZE 1024
#endif
typedef enum {
MRB_GC_STATE_ROOT = 0,
MRB_GC_STATE_MARK,
@@ -38,8 +42,9 @@ typedef struct mrb_gc {
struct mrb_heap_page *heaps; /* all heaps pages */
struct mrb_heap_page *free_heaps;/* heaps for allocation */
struct mrb_heap_page *sweeps; /* page where sweep starts */
struct RBasic *gray_list; /* list of gray objects to be traversed incrementally */
struct RBasic *atomic_gray_list; /* list of objects to be traversed atomically */
struct RBasic *gray_stack[MRB_GRAY_STACK_SIZE]; /* stack of gray objects */
size_t gray_stack_top; /* top index of gray stack */
mrb_bool gray_overflow:1; /* gray stack overflowed; needs heap rescan */
size_t live; /* count of live objects */
size_t live_after_mark; /* old generation objects */
size_t threshold; /* threshold to start GC */
+1 -1
View File
@@ -14,7 +14,7 @@
*/
MRB_BEGIN_DECL
/* offset of `iv` must be 3 words */
/* offset of `iv` must match struct RObject */
struct RHash {
MRB_OBJECT_HEADER;
#ifdef MRB_64BIT
+2 -3
View File
@@ -9,7 +9,6 @@
#define MRB_OBJECT_HEADER \
struct RClass *c; \
struct RBasic *gcnext; \
enum mrb_vtype tt:8; \
unsigned int gc_color:3; \
unsigned int frozen:1; \
@@ -39,7 +38,7 @@ struct RFiber {
};
#define mrb_static_assert_object_size(st) \
mrb_static_assert(sizeof(st) <= sizeof(void*) * 6, \
#st " size must be within 6 words")
mrb_static_assert(sizeof(st) <= sizeof(void*) * 5, \
#st " size must be within 5 words")
#endif /* MRUBY_OBJECT_H */