~ chicken-core (chicken-5) f1c620c8fd9432bcad57156151890b2138f9c6f8
commit f1c620c8fd9432bcad57156151890b2138f9c6f8
Author: megane <meganeka@gmail.com>
AuthorDate: Sun Jan 5 09:03:14 2020 +0200
Commit: Mario Domenech Goulart <mario@parenteses.org>
CommitDate: Fri Jan 8 20:10:52 2021 +0100
Prevent excessive major gcs by having decent amount of unused heap
Signed-off-by: Mario Domenech Goulart <mario@parenteses.org>
diff --git a/manual/Using the compiler b/manual/Using the compiler
index fd656362..7e8ff6de 100644
--- a/manual/Using the compiler
+++ b/manual/Using the compiler
@@ -223,6 +223,8 @@ by the startup code and will not be contained in the result of
; {{-:hmNUMBER}} : Specifies a maximal heap size (including both semispaces). The default is (2GB - 15).
+; {{-:hfNUMBER}} : If the free heap space is less than this number (8M by default), then the heap is grown. This is approximately the amount of generated heap garbage in bytes after which a major garbage collection will happen.
+
; {{-:hsPERCENTAGE}} : Sets the shrink rate of the heap in percent. The heap is shrunk to {{PERCENTAGE}} when the watermark is reached. The default is 50. Note: If you want to make sure that the heap never shrinks, specify a value of {{0}}. (this can be useful in situations where an optimal heap-size is known in advance).
; {{-:huPERCENTAGE}} : Sets the memory usage watermark below which heap shrinking is triggered. The default is 25.
diff --git a/runtime.c b/runtime.c
index a0b77bba..664e7a26 100644
--- a/runtime.c
+++ b/runtime.c
@@ -163,6 +163,7 @@ static C_TLS int timezone;
#define DEFAULT_HEAP_GROWTH 200
#define DEFAULT_HEAP_SHRINKAGE 50
#define DEFAULT_HEAP_SHRINKAGE_USED 25
+#define DEFAULT_HEAP_MIN_FREE (4 * 1024 * 1024)
#define DEFAULT_FORWARDING_TABLE_SIZE 32
#define DEFAULT_LOCATIVE_TABLE_SIZE 32
#define DEFAULT_COLLECTIBLES_SIZE 1024
@@ -360,6 +361,7 @@ C_TLS C_uword
C_heap_growth = DEFAULT_HEAP_GROWTH,
C_heap_shrinkage = DEFAULT_HEAP_SHRINKAGE,
C_heap_shrinkage_used = DEFAULT_HEAP_SHRINKAGE_USED,
+ C_heap_half_min_free = DEFAULT_HEAP_MIN_FREE,
C_maximal_heap_size = DEFAULT_MAXIMAL_HEAP_SIZE;
C_TLS time_t
C_startup_time_sec,
@@ -1368,6 +1370,7 @@ void CHICKEN_parse_command_line(int argc, char *argv[], C_word *heap, C_word *st
" -:o disable stack overflow checks\n"
" -:hiSIZE set initial heap size\n"
" -:hmSIZE set maximal heap size\n"
+ " -:hfSIZE set minimum unused heap size\n"
" -:hgPERCENTAGE set heap growth percentage\n"
" -:hsPERCENTAGE set heap shrink percentage\n"
" -:huPERCENTAGE set percentage of memory used at which heap will be shrunk\n"
@@ -1396,6 +1399,9 @@ void CHICKEN_parse_command_line(int argc, char *argv[], C_word *heap, C_word *st
*heap = arg_val(ptr + 1);
heap_size_changed = 1;
goto next;
+ case 'f':
+ C_heap_half_min_free = arg_val(ptr + 1);
+ goto next;
case 'g':
C_heap_growth = arg_val(ptr + 1);
goto next;
@@ -3565,23 +3571,40 @@ C_regparm void C_fcall C_reclaim(void *trampoline, C_word c)
}
update_locative_table(gc_mode);
- count = (C_uword)tospace_top - (C_uword)tospace_start;
-
- /*** isn't gc_mode always GC_MAJOR here? */
- /* NOTE: count is actual usage, heap_size is both halves */
- if(gc_mode == GC_MAJOR &&
- count < percentage(heap_size/2, C_heap_shrinkage_used) &&
- C_heap_shrinkage > 0 &&
- heap_size > MINIMAL_HEAP_SIZE && !C_heap_size_is_fixed)
- C_rereclaim2(percentage(heap_size, C_heap_shrinkage), 0);
- else {
- C_fromspace_top = tospace_top;
- tmp = fromspace_start;
- fromspace_start = tospace_start;
- tospace_start = tospace_top = tmp;
- tmp = C_fromspace_limit;
- C_fromspace_limit = tospace_limit;
- tospace_limit = tmp;
+ count = (C_uword)tospace_top - (C_uword)tospace_start; // Actual used, < heap_size/2
+
+ {
+ C_uword min_half = count + C_heap_half_min_free;
+ C_uword low_half = percentage(heap_size/2, C_heap_shrinkage_used);
+ C_uword grown = percentage(heap_size, C_heap_growth);
+ C_uword shrunk = percentage(heap_size, C_heap_shrinkage);
+
+ /*** isn't gc_mode always GC_MAJOR here? */
+ if(gc_mode == GC_MAJOR && !C_heap_size_is_fixed &&
+ C_heap_shrinkage > 0 &&
+ count < low_half &&
+ (min_half * 2) <= shrunk && // Min. size trumps shrinkage
+ heap_size > MINIMAL_HEAP_SIZE) {
+ if(gc_report_flag) {
+ C_dbg(C_text("GC"), C_text("Heap low water mark hit (%d%%), shrinking...\n"),
+ C_heap_shrinkage_used);
+ }
+ C_rereclaim2(shrunk, 0);
+ } else if (gc_mode == GC_MAJOR && !C_heap_size_is_fixed &&
+ (heap_size / 2) < min_half) {
+ if(gc_report_flag) {
+ C_dbg(C_text("GC"), C_text("Heap high water mark hit, growing...\n"));
+ }
+ C_rereclaim2(grown, 0);
+ } else {
+ C_fromspace_top = tospace_top;
+ tmp = fromspace_start;
+ fromspace_start = tospace_start;
+ tospace_start = tospace_top = tmp;
+ tmp = C_fromspace_limit;
+ C_fromspace_limit = tospace_limit;
+ tospace_limit = tmp;
+ }
}
never_mind_edsger:
Trap