From 07b8a5b0427c21518c7b7cf465197dc310b9d3b0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 22 Nov 2013 09:20:06 +0900 Subject: Make mrb->arena variable sized. Use MRB_GC_FIXED_ARENA for old behavior. You will not see "arena overflow" error anymore, but I encourage gem authors to check your gems with MRB_GC_FIXED_ARENA to avoid memory broat. --- include/mrbconf.h | 6 ++++++ include/mruby.h | 11 ++++++++--- src/gc.c | 24 ++++++++++++++++++++++-- src/state.c | 8 ++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/include/mrbconf.h b/include/mrbconf.h index a10a1d04e..5c745f479 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -59,6 +59,12 @@ /* array size for parser buffer */ //#define MRB_PARSER_BUF_SIZE 1024 +/* arena size */ +//#define MRB_GC_ARENA_SIZE 100 + +/* fixed size GC arena */ +//#define MRB_GC_FIXED_ARENA + /* -DDISABLE_XXXX to drop following features */ //#define DISABLE_STDIO /* use of stdio */ diff --git a/include/mruby.h b/include/mruby.h index e70487f27..882ba4e07 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -46,8 +46,8 @@ struct mrb_state; typedef void* (*mrb_allocf) (struct mrb_state *mrb, void*, size_t, void *ud); -#ifndef MRB_ARENA_SIZE -#define MRB_ARENA_SIZE 100 +#ifndef MRB_GC_ARENA_SIZE +#define MRB_GC_ARENA_SIZE 100 #endif typedef struct { @@ -128,7 +128,12 @@ typedef struct mrb_state { struct heap_page *sweeps; struct heap_page *free_heaps; size_t live; /* count of live objects */ - struct RBasic *arena[MRB_ARENA_SIZE]; /* GC protection array */ +#ifdef MRB_GC_FIXED_ARENA + struct RBasic *arena[MRB_GC_ARENA_SIZE]; /* GC protection array */ +#else + struct RBasic **arena; /* GC protection array */ + int arena_capa; +#endif int arena_idx; enum gc_state gc_state; /* state of gc */ diff --git a/src/gc.c b/src/gc.c index a1ff4d32b..5592b48f1 100644 --- a/src/gc.c +++ b/src/gc.c @@ -370,10 +370,16 @@ mrb_free_heap(mrb_state *mrb) static void gc_protect(mrb_state *mrb, struct RBasic *p) { - if (mrb->arena_idx >= MRB_ARENA_SIZE) { + if (mrb->arena_idx >= MRB_GC_ARENA_SIZE) { +#ifdef MRB_GC_FIXED_ARENA /* arena overflow error */ - mrb->arena_idx = MRB_ARENA_SIZE - 4; /* force room in arena */ + mrb->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */ mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error"); +#else + /* extend arena */ + mrb->arena_capa *= 1.5; + mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*mrb->arena_capa); +#endif } mrb->arena[mrb->arena_idx++] = p; } @@ -1041,6 +1047,20 @@ mrb_gc_arena_save(mrb_state *mrb) void mrb_gc_arena_restore(mrb_state *mrb, int idx) { +#ifndef MRB_GC_FIXED_ARENA + int capa = mrb->arena_capa; + + if (idx < capa / 2) { + capa *= 0.66; + if (capa < MRB_GC_ARENA_SIZE) { + capa = MRB_GC_ARENA_SIZE; + } + if (capa != mrb->arena_capa) { + mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*capa); + mrb->arena_capa = capa; + } + } +#endif mrb->arena_idx = idx; } diff --git a/src/state.c b/src/state.c index f8a97cb61..00e113998 100644 --- a/src/state.c +++ b/src/state.c @@ -42,6 +42,11 @@ mrb_open_allocf(mrb_allocf f, void *ud) mrb->allocf = f; mrb->current_white_part = MRB_GC_WHITE_A; +#ifndef MRB_GC_FIXED_ARENA + mrb->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE); + mrb->arena_capa = MRB_GC_ARENA_SIZE; +#endif + mrb_init_heap(mrb); mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context)); *mrb->c = mrb_context_zero; @@ -191,6 +196,9 @@ mrb_close(mrb_state *mrb) mrb_free_symtbl(mrb); mrb_free_heap(mrb); mrb_alloca_free(mrb); +#ifndef MRB_GC_FIXED_ARENA + mrb_free(mrb, mrb->arena); +#endif mrb_free(mrb, mrb); } -- cgit v1.2.3