summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2020-07-31 21:39:47 +0300
committerIvan Maidanski <ivmai@mail.ru>2020-07-31 22:03:50 +0300
commit2bff37a90ff13c256f6ffd59a69b60b45ab7cab0 (patch)
tree3076c1012701224b2daebd68df8ae24edaf27571
parent802e47d5e8dcbddd2e80cd4587eacc5f4ffbc745 (diff)
downloadbdwgc-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.c26
-rw-r--r--doc/README.macros3
-rw-r--r--include/gc.h23
-rw-r--r--tests/test.c2
4 files changed, 52 insertions, 2 deletions
diff --git a/alloc.c b/alloc.c
index 8a2a07d9..29685eae 100644
--- a/alloc.c
+++ b/alloc.c
@@ -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);