Why many programmers don't like GC?

tsbockman thomas.bockman at gmail.com
Wed Jan 13 20:36:05 UTC 2021


On Wednesday, 13 January 2021 at 18:58:56 UTC, Marcone wrote:
> I've always heard programmers complain about Garbage Collector 
> GC. But I never understood why they complain. What's bad about 
> GC?

SHORT VERSION: While garbage collection is great for many 
applications, GC also has some significant disadvantages. As a 
systems programming language, D attracts users who care about the 
disadvantages of GC, but D's design prevents it from mitigating 
the downsides of GC to the extent that less powerful languages 
like Java can.

LONG VERSION: There are many different garbage collector designs, 
so not all of these criticisms apply to all garbage collector 
designs. Nevertheless, most every design suffers from at least 
some of these problems:

1) Freezes/pauses: many garbage collectors have to pause all 
other threads in the program for some significant time in order 
to collect. This takes somewhere between a few ms and a few s, 
depending on how much data needs to be scanned.

For interactive applications, these pauses can cripple the 
program's performance. 60 FPS, or 16ms per frame, is a typical 
target rate for modern user interfaces, video playback, and 
games. When any given frame may be subject to a 5ms pause by the 
GC, the processing for *every* frame must be limited to what can 
be accomplished in 11ms, effectively wasting 30% of the available 
CPU performance of *all cores* on most frames, when no collection 
was necessary. But, 5ms is on the low end for GC pauses. Pauses 
longer than 16ms are common with some GC designs, guaranteeing 
dropped frames which are distracting and unpleasant to the user.

For real-time applications such as hardware control systems, a 
pause that is too long could actually break something or injure 
someone.

2) Much higher memory consumption: all practical heap memory 
management schemes have some overhead - additional memory that is 
consumed by the manager itself, rather than the rest of the 
program's allocations. But, garbage collectors typically require 
three to ten times the size of the data for good performance, as 
opposed to two times or less for reference counting or manual 
management.

3) RAII doesn't work properly because the GC usually doesn't 
guarantee that destructors will be run for objects that it frees. 
I don't know why this is such a common limitation, but my guess 
is that it is due to one or both of:
     a) Collection often happens on a different thread from an 
object's allocation and construction. So, either all destructors 
must be thread-safe, or they just can't be run.
     b) A collection may occur at some awkward point where the 
program invariants depended on by non thread-safe destructors are 
violated, like inside of another destructor.

It is certainly possible to retrofit correct resource management 
on top of a GC scheme, but the logic required to determine when 
to close file handles (for example) is often the same as the 
logic required to determine when memory can safely be freed, so 
why not just combine the two and skip the GC?

GC has significant advantages, of course: simplicity (outside the 
GC itself), safety, and, for better designs, high throughput. 
But, the D users are more critical of GC than most for good 
reason:

I) D is a systems programming language. While a good GC is the 
best choice for many, many applications, the kinds of 
applications for which GC is inappropriate usually require, or at 
least greatly benefit from, the full power of a systems 
programming language. So, the minority of programmers who have 
good reason to avoid GC tend to leave other languages like Java, 
C#, python, and JavaScript and come to us (or C, C++, Zig, or 
Rust).

II) Historically, D's GC was embarrassingly bad compared to the 
state-of-the-art designs used by the JVM and .NET platforms. D's 
GC has improved quite a lot over the years, but it is not 
expected to ever catch up to the really good ones, because it is 
limited by other design decisions in the D language that 
prioritize efficient, easy-to-understand interoperability with 
C-style code over having the best possible GC.

In particular, D's GC is a stop-the-world design that must pause 
*all* threads that may own any GC memory whenever it collects, 
and thus it fully suffers from problem (1) which I described 
earlier. Also, it used to have the additional problem that it 
leaked memory by design (not a bug). This is mostly fixed now, 
but for some reason the fix is not enabled by default?! 
https://dlang.org/spec/garbage.html#precise_gc

(In before someone answers with, "Nothing. It works for me, so 
people who say it's bad are just stupid and don't profile.")


More information about the Digitalmars-d-learn mailing list