Hacker News new | ask | show | jobs
by weberc2 2555 days ago
C++ still needs to allocate and free memory too and for all we know naive C++ might spend more time in memory management code than a GC language.
3 comments

There is a fair bit of C++ code in use. We have no need to guess.

And, the answer is that real programs in obligate-GC languages spend overwhelmingly more time in GC than C++ or Rust. Much of this time is spent waiting on cache misses, which are hard to track to the responsible bit of code.

Do you have evidence for this? Specifically C++ and Rust tend to be written for applications where tight control over memory is necessary and so any sample like you're describing is going to be biased by these carefully tuned C++/Rust applications. Even the standard libraries for C++ and Rust differ considerably in allocation behavior from Java or Python--these languages are conventionally designed to allocate differently, but that doesn't mean that the GC is the problem. Further, different programming paradigms allocate memory differently and the distribution of these paradigms across GC languages and non-GC languages (or whatever terms you like) are almost certainly varied. There are lots of confounding variables to control for, and until you control for them you're pretty much just guessing.
I think it's pretty obvious if you use these languages. A lot of things that require you to heap allocate in Java or Python (like classes!) have stack-allocated versions in rust/c++. Which means that code which avoids slow heap allocation is much nicer than equiavlent code in Java that must avoid high level abstractions.

You're right that the GC isn't necessarily the issue. It's more the forced heap allocation which most GC languages come with.

Agreed, although to pick a nit (because it's an interesting nit IMO) "Classes" is orthogonal to allocation. In C++ you choose where you allocate your class and in Java the escape analyzer chooses for you. C# and Go have a GC and (more or less) semantics for heap-vs-stack allocation.
That heap allocation is most likely either optimized away and allocated in stack/ allocated in minor heap which is same as bumping a pointer just like in stack!
Only for Java, not Python. And in any case, the cache performance will still be worse, but that’s a more minor cost.
> ...for all we know naive C++ might spend more time in memory management code than a GC language.

That's actually true, as long as all things are equal. GC can amortize memory management cost. Of course at cost of more jitter.

Unfortunately many GC language users tend to do way more allocations as well, diminishing the advantage and even turning it into negative.

>we know naive C++ might spend more time in memory management code than a GC language.

That's not really true anymore after the introduction of smart pointers. Basically C++ implements reference counting to manage memory as a result.

Smart pointers make no difference to the time spent allocating and freeing memory.

But we know that GC always imposes huge costs that point benchmarks uniformly fail to reveal. Often the costs are tolerable, or even negligible. At issue is the set of recourses available when they turn out not to be.

In what regard? GC just amortizes the cost. But memory allocation doesn't fundamentally work any differently.

In fact, it can be worse in Java because you have no control over whether an object lives on the stack instead of the heap.

No. GC imposes expense in addition to actually managing the memory in use, or newly not. If that were not true, there would be no reduction in hardware footprint after a rewrite.

Make no mistake, rewriting is a huge expense, rarely embarked upon without readily demonstrated benefit. (Exceptions tend to be rewrites in Java for organizational / political reasons. But I digress.) Not spending the time, instead, adding features, and delaying new features until there is a place to put them, can dwarf the base cost of the rewrite. That rewrites are done frequently enough to be discussed tells you there are huge operational benefits available.

The OP mentioned nothing about organizational costs, I was talking purely about performance. The OP was incorrectly claiming you'd spend more time in C++ allocating memory, not less.
Your argument is puzzling. Reference counting is a particularly slow kind of GC. It makes you spend more time freeing memory, not less. And it does nothing to reduce the cost of allocations either. On the contrary, a generational GC can allocate short-lives objects virtually for free—much better than the system allocator. The advantage C++ does have is the ability to control memory such that you can write memory reclamation code that is optimized to your particular application, leveraging information that simply isn’t available to a GC.
Well said, although that's not the only thing at issue; the prominent tradeoff for that generally smaller (or less powerful) set of recourses is that you have easy, automatic memory management for the default case. I.e., you don't need to make decisions about how memory is managed unless you need to make those decisions. In C++ and Rust, you have to constantly make those decisions (which kind of pointer to use, where will it allocate, what happens to ownership, how will this affect callers, etc).
"We know". Where is the evidence?