diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2020-07-31 21:39:47 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2020-07-31 22:03:50 +0300 |
commit | 2bff37a90ff13c256f6ffd59a69b60b45ab7cab0 (patch) | |
tree | 3076c1012701224b2daebd68df8ae24edaf27571 | |
parent | 802e47d5e8dcbddd2e80cd4587eacc5f4ffbc745 (diff) | |
download | bdwgc-2bff37a90ff13c256f6ffd59a69b60b45ab7cab0.tar.gz |
Do not hard-code finalizable objects limit which triggers GC
Issue #304 (bdwgc).
Previously, if more than 500 finalizable objects emerged since the
latest collection (and the incremental mode is off), then new
collection is started instead heap expansion. This led to frequent
collections if most allocated objects were with a registered finalizer.
Now, the hard coded limit (500) is replaced roughly with
(GC_bytes_allocd / GC_allocd_bytes_per_finalizer), where the latter
global variable has the default value of 10000 (or
GC_ALLOCD_BYTES_PER_FINALIZER if defined) but could be changed by the
client with GC_set_allocd_bytes_per_finalizer().
* alloc.c (GC_allocd_bytes_per_finalizer): New STATIC variable
(initialized to GC_ALLOCD_BYTES_PER_FINALIZER if defined otherwise to 10000).
* alloc.c (GC_set_allocd_bytes_per_finalizer,
GC_get_allocd_bytes_per_finalizer): New API function definition.
* alloc.c (GC_collect_or_expand): Replace
GC_fo_entries>last_fo_entries+500 condition to
GC_fo_entries>last_fo_entries &&
(GC_fo_entries-last_fo_entries)*GC_allocd_bytes_per_finalizer
>GC_bytes_allocd.
* doc/README.macros (GC_ALLOCD_BYTES_PER_FINALIZER): Document.
* include/gc.h (GC_set_allocd_bytes_per_finalizer,
GC_get_allocd_bytes_per_finalizer): New API function declaration.
* include/gc.h (GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER): New internal
macro (call GC_set_allocd_bytes_per_finalizer if
GC_ALLOCD_BYTES_PER_FINALIZER is defined by client).
* include/gc.h (GC_INIT): Call GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER.
* tests/test.c [!PCR && !GC_WIN32_THREADS && !GC_PTHREADS && CPPCHECK]
(main): Call UNTESTED() for GC_get_allocd_bytes_per_finalizer and
GC_set_allocd_bytes_per_finalizer.
-rw-r--r-- | alloc.c | 26 | ||||
-rw-r--r-- | doc/README.macros | 3 | ||||
-rw-r--r-- | include/gc.h | 23 | ||||
-rw-r--r-- | tests/test.c | 2 |
4 files changed, 52 insertions, 2 deletions
@@ -1490,6 +1490,26 @@ GC_INNER unsigned GC_fail_count = 0; /* How many consecutive GC/expansion failures? */ /* Reset by GC_allochblk. */ +/* The minimum value of the ratio of allocated bytes since the latest */ +/* GC to the amount of finalizers created since that GC which triggers */ +/* the collection instead heap expansion. Has no effect in the */ +/* incremental mode. */ +#if defined(GC_ALLOCD_BYTES_PER_FINALIZER) && !defined(CPPCHECK) + STATIC word GC_allocd_bytes_per_finalizer = GC_ALLOCD_BYTES_PER_FINALIZER; +#else + STATIC word GC_allocd_bytes_per_finalizer = 10000; +#endif + +GC_API void GC_CALL GC_set_allocd_bytes_per_finalizer(GC_word value) +{ + GC_allocd_bytes_per_finalizer = value; +} + +GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void) +{ + return GC_allocd_bytes_per_finalizer; +} + static word last_fo_entries = 0; static word last_bytes_finalized = 0; @@ -1509,8 +1529,10 @@ GC_INNER GC_bool GC_collect_or_expand(word needed_blocks, DISABLE_CANCEL(cancel_state); if (!GC_incremental && !GC_dont_gc && ((GC_dont_expand && GC_bytes_allocd > 0) - || (GC_fo_entries > (last_fo_entries + 500) - && (last_bytes_finalized | GC_bytes_finalized) != 0) + || (GC_fo_entries > last_fo_entries + && (last_bytes_finalized | GC_bytes_finalized) != 0 + && (GC_fo_entries - last_fo_entries) + * GC_allocd_bytes_per_finalizer > GC_bytes_allocd) || GC_should_collect())) { /* Try to do a full collection using 'default' stop_func (unless */ /* nothing has been allocated since the latest collection or heap */ diff --git a/doc/README.macros b/doc/README.macros index 5d4a198b..1fd1f321 100644 --- a/doc/README.macros +++ b/doc/README.macros @@ -571,6 +571,9 @@ GC_INITIAL_HEAP_SIZE=<value> Set the desired default initial heap size GC_FREE_SPACE_DIVISOR=<value> Set alternate default GC_free_space_divisor value. +GC_ALLOCD_BYTES_PER_FINALIZER=<value> Set alternate default value of + GC_allocd_bytes_per_finalizer. + GC_TIME_LIMIT=<milliseconds> Set alternate default GC_time_limit value (setting this to GC_TIME_UNLIMITED will essentially disable incremental collection while leaving generational collection enabled). diff --git a/include/gc.h b/include/gc.h index fc04d90d..17742b0b 100644 --- a/include/gc.h +++ b/include/gc.h @@ -417,6 +417,20 @@ struct GC_timeval_s { GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s); GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void); +/* Set/get the minimum value of the ratio of allocated bytes since GC */ +/* to the amount of finalizers created since that GC (value > */ +/* GC_bytes_allocd / (GC_fo_entries - last_fo_entries)) which triggers */ +/* the collection instead heap expansion. The value has no effect in */ +/* the GC incremental mode. The default value is 10000 unless */ +/* GC_ALLOCD_BYTES_PER_FINALIZER macro with a custom value is defined */ +/* to build libgc. The default value might be not the right choice for */ +/* clients where e.g. most objects have a finalizer. Zero value */ +/* effectively disables taking amount of finalizers in the decision */ +/* whether to collect or not. The functions do not use any */ +/* synchronization. */ +GC_API void GC_CALL GC_set_allocd_bytes_per_finalizer(GC_word); +GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void); + /* Tell the collector to start various performance measurements. */ /* Only the total time taken by full collections is calculated, as */ /* of now. And, currently, there is no way to stop the measurements. */ @@ -1993,6 +2007,14 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void); # define GC_INIT_CONF_MAX_RETRIES /* empty */ #endif +#if defined(GC_ALLOCD_BYTES_PER_FINALIZER) && !defined(CPPCHECK) + /* Set GC_allocd_bytes_per_finalizer to the desired value at start-up. */ +# define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER \ + GC_set_allocd_bytes_per_finalizer(GC_ALLOCD_BYTES_PER_FINALIZER) +#else +# define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER /* empty */ +#endif + #if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK) /* Set GC_free_space_divisor to the desired value at start-up */ # define GC_INIT_CONF_FREE_SPACE_DIVISOR \ @@ -2062,6 +2084,7 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void); #define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; /* pre-init */ \ GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT; \ GC_INIT_CONF_MAX_RETRIES; \ + GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER; \ GC_INIT_CONF_FREE_SPACE_DIVISOR; \ GC_INIT_CONF_FULL_FREQ; \ GC_INIT_CONF_TIME_LIMIT; \ diff --git a/tests/test.c b/tests/test.c index e2ebc259..f3623d15 100644 --- a/tests/test.c +++ b/tests/test.c @@ -1993,6 +1993,7 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) UNTESTED(GetSymbolNameFromStack); # endif UNTESTED(GC_abort_on_oom); + UNTESTED(GC_get_allocd_bytes_per_finalizer); UNTESTED(GC_get_bytes_since_gc); UNTESTED(GC_get_dont_expand); UNTESTED(GC_get_dont_precollect); @@ -2015,6 +2016,7 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) UNTESTED(GC_get_time_limit); UNTESTED(GC_get_warn_proc); UNTESTED(GC_is_disabled); + UNTESTED(GC_set_allocd_bytes_per_finalizer); UNTESTED(GC_set_dont_precollect); UNTESTED(GC_set_finalize_on_demand); UNTESTED(GC_set_finalizer_notifier); |