GC and memory-hungry parallel threads
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
New
|
Undecided
|
Unassigned |
Bug Description
This is (at least) a specific case of "wanting a better documentation on tuning the GC",
see https:/
When running multiple threads in parallel, SBCL tends to exhaust its heap during GC
even though only a small fraction of the dynamic-space-size is used for live data
at any time. Specifically, in a 64bit VM with a 4Gb dynamic-space-size for SBCL
and 5 parallel worker threads, temporarily allocating 5000 * (2500 * 8 bytes) = 100MB
each time, the live data should not be much more than 500MB total at any time,
which is just 1/8 of the available space. Is this expected?
For the development of a web-application, we need to know how much live data SBCL can safely accomodate.
What is the worst-case memory requirement factor for a given amount of live data?
Is it really 2 * (1+ highest-
Can this ratio be improved, maybe by using fewer generations? How?
Does it make sense to build SBCL for SMP with a non-generational GC? Is it possible?
Could it be a workaround to manually trigger a :full GC at some point when it's still safe?
How to tune the GC for a robust web-application with many worker threads and varying allocations?
Useful references:
http://
http://
http://
Testcase (see attachment):
1. build executable with
sbcl --dynamic-
2. run e.g. like this:
./gc-
$ sbcl --version
SBCL 1.1.9.4-220651c
$ uname -a
Linux leo-2013 2.6.32-
* *features*
(:ALIEN-CALLBACKS :ANSI-CL :ASH-RIGHT-VOPS :C-STACK-
:COMMON-LISP :COMPARE-
:FLOAT-EQL-VOPS :GENCGC :IEEE-FLOATING-
:LINKAGE-TABLE :LINUX :LITTLE-ENDIAN :MEMORY-
:OS-PROVIDES-
:OS-PROVIDES-
:OS-PROVIDES-
:SB-DOC :SB-EVAL :SB-FUTEX :SB-LDB :SB-PACKAGE-LOCKS :SB-SIMD-PACK
:SB-SOURCE-
:STACK-
:STACK-
:STACK-
Attaching dynamic usage graphs for 5 testcases: parallel. exe --parallel 5 --size 2500 --count 5000 --total 100000 parallel. exe --parallel 5 --size 2500 --count 5000 --total 10000 parallel. exe --parallel 5 --size 2500 --count 5000 --with-extra-gc t parallel. exe --parallel 5 --size 2500 --count 5000 --with-extra-sleep 0.01 clear-cells: gc-stress- parallel. exe --parallel 5 --size 2500 --count 5000 --with-clear-cells nil
default: gc-stress-
default2: gc-stress-
with-extra-gc: gc-stress-
with-extra-sleep: gc-stress-
without-
Note that clearing out the list cells referencing the garbage makes a huge difference:
without it, the heap exhaustion occurs already after <1000 iterations:
#iterations until out-of-heap dynamic- space-usage_ _parallel- 5__size- 2500__count- 5000.csv dynamic- space-usage_ _parallel- 5__size- 2500__count- 5000.csv gc/dynamic- space-usage_ _parallel- 5__size- 2500__count- 5000__gc- T.csv sleep/dynamic- space-usage_ _parallel- 5__size- 2500__count- 5000__sleep- 0.01.csv clear-cells/ dynamic- space-usage_ _parallel- 5__size- 2500__count- 5000.csv
1666 default/
2289 default2/
2505 with-extra-
2528 with-extra-
544 without-