Hacker News new | ask | show | jobs
by bitwize 2012 days ago
> Common Lisp has extremely good compilers that can meet C performance.

Provided memory is no object.

In general it takes five times as much memory for a GC'd program to be as performant as one with explicit memory management. See: https://www.cics.umass.edu/~emery/pubs/gcvsmalloc.pdf

There's a reason why the most interesting work these days is being done in and on languages like Rust, which has no GC but still saves you 90% of the work and close to 100% of the pain of bugs that are inherent to explicit memory management.

3 comments

Usually it boils down to cargo cult against GC based languages instead of learning how to use all their features, including those for C++ like resource management.

https://devblogs.microsoft.com/aspnet/grpc-performance-impro...

While I can't speak for any experimental new garbage collectors, I did analyze the SBCL generational GC's implementation. I encourage anyone interested in performance to look over GC code and realize how much work they are doing.

That GC in particular has to stop the world, traverse the entire fresh heap, guesses whether something is even a pointer (and can guess wrong, causing a memory leak!), and does all this at arbitrary times, unless you do non-idiomatic things like manage your own memory in preallocated arrays, or use C/asm-powered memory mapped buffers [0].

Nothing comes for free, and some domains can't pay the price for GC (and choose to spend those resources elsewhere). Games, in my opinion, are largely still in that category.

[0] https://m.youtube.com/watch?v=S7nEZ3TuFpA

> unless you do non-idiomatic things

I wonder what exactly makes code "idiomatic" in a GC language. It is one of the greatest misconceptions about GC languages that you shouldn't worry about allocations at all. For me, GC mostly means the correctness guarantees which come with it and the convenience, that I don't have to track every single allocation and mange it manually. However, it still means that I should be aware of all the larger allocations and avoid them as in any other language, if I am looking for performance. Not reusing allocated memory where reasonable is detrimental to the performance in any language. And of course, the choice of the right GC approach can also help with applications like games. Lispworks even provided a Lisp environment for a Nasa probe, the GC had real-time capabilities.

Like the ones written in Unreal?

https://docs.unrealengine.com/en-US/ProgrammingAndScripting/...

Just because a language has a GC doesn't mean one needs to use it 100% of the time, which is exactly what is behind the .NET 5 performance improvements that top C++.

By making use of stack allocations, value types, memory slices, native heap allocations.

Features that Common Lisp also supports, and I bet Allegro and LispWorks are better than SBCL in the performance chapter.

It depends on what you talk about with "performance". Some years ago, Allegro had the faster GC than SBCL, but SBCL certainly had the best code generator of the three Lisps. So unless your runtime is constrained by the GC, SBCL really shines for performance. And it gives you a lot of knobs to optimize the memory usage.
SBCL generates the best code for toy benchmarks and number crunching applications. Throw it against a CLOS heavy codebase and you'll be surprised at how it runs VS Clozure CL and the aforementioned implementations.

ACL's GC is still the best hands down (and of course ABCL by virtue of the JVM). I think SBCL is still sporting a conservative GC on x86.

Not sure what you meant by "toy benchmarks", but to me this has a very negative connotation. The SBCL compiler excells at complex code and regularly produces much better output than most Lisp compilers. CLOS is a very bad example for judging the compiler quality, because its performance heavily depends on the implementation. To compare compilers, you would have to use the identical underlying CLOS implementation. A bad one can ruin your performance independantly of the compiler used. To make comparisons, one needs benchmarks where the whole code in question is compiled by the different compilers.

To my knowledge, SBCL switched to a precise GC some time ago. But I still would expect ACL's GC to outperform the SBCL one.

> In general it takes five times as much memory for a GC'd program to be as performant as one with explicit memory management.

In this blanket form, the statement is just wrong. Yes, with GC you need to have a larger heap space, as unreferenced objects will remain on the heap until collected and you want to have enough heap space so collections are infrequent enough, that a lot of objects can be collected (especially with generational GC, you want low survivor rates in the youngest generation).

However, how much space you want to reserve for that depends on many factors. Usually the extra space is proportional to the allocation and deallocation rates, not the total heap size. If you have lots of data on the heap which is long-living, this doesn't count to the extra space. Which leads to the allocation behavior of your program in general. If you want best performance, your program shouldn't blindly create garbage, but only, where it is needed. A lot of data can be stack allocated, so not counting towards the GC. And of course, you can have some amount of memory manually managed (depending on language), for bulk data. Be it entirely allocated outside the GCed heap or by keeping references alive to memory that manually gets reused. In all of these cases, this doesn't really count towards the extra space calculation.

The programming language used plays a huge role in this and the paper you quoted uses Java, which is a quite allocation-happy language, so the heap pressure is higher and you need more extra space to be performant.

At 3x memory you still get comparable performance, and memory is fairly cheap. In particular, memory sizes continue to scale, unlike CPU speeds, making GC an increasingly favourable proposition.
The end result is games that use 8GB of RAM like modded Minecraft. I was perfectly happy with 8GB of RAM for the entire system but no, that one game was so inefficient that I had to upgrade my entire system.

I will keep saying this over and over again. It's only cheap if you don't waste it. Once you are willing to waste it no amount of RAM will be good enough.