3 ms·
This can be easily illustrated using this example [1], which uses both the Boehm GC (v8.0.2) and jemalloc (v5.0.1), directly installed via Homebrew, as well as
by rbehrends 8y ago
This can be easily illustrated using this example [1], which uses both the Boehm GC (v8.0.2) and jemalloc (v5.0.1), directly installed via Homebrew, as well as the system malloc on macOS to implement the binary trees benchmark from the benchmark game.
The benchmark keeps a large live set and allocates aggressively, making it an unattractive scenario for many GCs.
The Boehm GC is being run with the following four distinct configurations:
- Four marker threads in parallel, trading CPU time for wall clock time and lower pause times.
- Single-threaded marking.
- GC disabled, all memory is freed explicitly.
- Incremental collection (using virtual memory).
The results, run on a Macbook Pro with a six core 2.6 GHz Core i7:
$ make benchmark DEPTH=21
# jemalloc explicit malloc()/free()
/usr/bin/time ./btree-jemalloc 21 >/dev/null
17.53 real 17.40 user 0.11 sys
# Boehm GC with four parallel marker threads
GC_MARKERS=4 /usr/bin/time ./btree-gc 21 >/dev/null
8.50 real 10.87 user 0.09 sys
# Boehm GC with single-threaded marking
GC_MARKERS=1 /usr/bin/time ./btree-gc 21 >/dev/null
10.40 real 10.33 user 0.05 sys
# Boehm GC with explicit deallocation
GC_MARKERS=1 /usr/bin/time ./btree-gc-free 21 >/dev/null
11.75 real 11.70 user 0.04 sys
# Boehm GC with incremental collection (single-threaded)
/usr/bin/time ./btree-gc-inc 21 >/dev/null
18.39 real 16.40 user 5.11 sys
# System malloc()/free()
/usr/bin/time ./btree-sysmalloc 21 >/dev/null
64.43 real 63.69 user 0.71 sys
Obviously, one should not read too much into this, as this is a very specific scenario with its own very specific allocation behavior that will not match other use cases. And one can speed up this specific example easily with a specialized allocator (as all allocations have the same size and predictable lifetime). Plus, different GCs make different tradeoffs, and so do general purpose manual allocators.
But for throughput at least, the worries about GC overhead tend to be exaggerated.
In practice, any language with proper value types will also spend only a fairly small fraction on allocation and garbage collection, so overhead becomes less of a problem.
[1] https://gist.github.com/rbehrends/528fc713c24195b1c8aefda074b281ec https://gist.github.com/rbehrends/528fc713c24195b1c8aefda074...