Live data from Hacker News

Reference count, don't garbage collect

kevinlawler.com

411–415 of 415 posts

Re: Reference count, don't garbage collect

#411
post #216

Earlier quoted context omitted.

Well, it won’t be the bottleneck itself, but it has an overhead on basically every operation, which likely won’t show up during profiling. Also, I fail to see the advantage of RC in case of a presumably mostly immutable language - a tracing GC is even faster there due to no changes to the object graph after allocation, making a generational approach scale very well and be almost completely done in parallel.

Nope. The compiler does a full program optimisation, reducing the reference counting to an absolute minimum. There is close to zero overhead passing data around. It does not work like C++ shared_pre. shared_ptr is slow .

> The compiler does a full program optimisation

That's the equivalent of an escape analysis I assume, which optimization exists for tracing GCs as well.

Re: Reference count, don't garbage collect

#412
post #391
post #362

Earlier quoted context omitted.

The android/iOS comparison has many more factors than GC type. I suspect the main difference is processor type - Qualcomm ARM has been very disappointing so far, and GC type doesn't even come into it.

Certainly, but Apple code also run on x86. My main point actually is that Apple don't pick this route for the fun of it. It HAS a need to be performant on mobiles devices (that have less luxury to get a GC that eat Ram) and that need represent A LOT OF MONEY. You can say any step about this, including making processors, are directly or indirectly related to the need. P.D: I don't see Rc VS Gc as enemies, but as faces…

Performance, right => https://github.com/ixy-languages/ixy-languages

Re: Reference count, don't garbage collect

#413

Earlier quoted context omitted.

> However, I doubt the efficacy of your C++ experts: most of the people I know who write C++ are actually really bad at optimizing code. Which is a very good reason to develop an optimized GC algorithm, the domain experts can crank out code without having to optimize every single memory (de)allocation which sounds like a waste of their time. It’s funny, people don’t usually doubt that a modern compiler can do a bette…

Personally, I think non-GC languages are very much overused. If you are writing business logic, and not counting cycles (even worse - if you are never planning to count cycles), you should probably not use C++ or Rust. However, a GC is a lot slower than manual memory management, which contrasts with the fact that most compiler activities are actually pretty low in overhead (now - it didn't used to be this way). Reall…

> However, a GC is a lot slower than manual memory management, which contrasts with the fact that most compiler activities are actually pretty low in overhead (now - it didn't used to be this way). Really, the only cost overhead left is the abstraction mismatch, and that is not too bad, when you compare to how bad humans are at writing assembly.

There is a triangle of GC performance; througput, latency (i.e. pause length), and memory overhead. Manual memory management will often be slower (in the throughput sense) than a throughput-tuned GC because:

1. Manual memory management typically precludes moving live data

2. Manual memory management often frees data as soon as it is dead

GC will often have faster allocations than manual memory management because #1 makes it possible to just use a pointer-increment for allocation. GC will often have faster freeing of data because of #2; in particular using a nursery with Cheney's algorithm makes it O(1) to free an arbitrary amount of data.

Where a throughput optimized GC falls down is in that any code that allocates may have an unpredictable amount of delay.

Also note that for video games, both typical GC and malloc/free are often too slow for per-frame data, so arena allocators are used, which sidestep #2, and allow a pointer-increment allocation without needing #1. This is specifically because there are a lot of objects with exactly the same bounds on their lifetime. Special-purpose algorithms will almost always trump general-purpose algorithms when run on the workload they are optimized for.

Re: Reference count, don't garbage collect

#414

Earlier quoted context omitted.

For ZGC/Shenandoah because they're new, and they're new because they're extremely hard to implement well. For C4 because it is expensive and requires kernel patches. Also there isn't a whole lot of need for them in many use cases. Web servers for example have far bigger latency problems than GC, normally. Pauseless GC was historically driven by the HFT/finance sector for that reason. Also yes, pauseless GC tends to h…

Thank you. I didn't know that one GC that I regularly use (as a user) - the one in Android - is so advanced these days. Interesting!

ART is a pretty astoundingly advanced JVM which gets nearly no publicity. It's a real shame. I bet a properly supported desktop version would be quite competitive with HotSpot!

https://source.android.com/devices/tech/dalvik/gc-debug#art_...

It also does mixed AOT / JITC, amongst other tricks.

Re: Reference count, don't garbage collect

#415
post #217

Earlier quoted context omitted.

If you are assuming GC does not need to stop the world, you can also assume that the freeing of memory (including the O(n) calls to free()) will not be done in a critical path; all memory could be handed off to a separate dedicated thread that actually calls free(). Or in a RPC or HTTP server all memory can be freed after the request has been served. It's very easy to make a reference counting scheme not stop the wor…

> all memory could be handed off to a separate dedicated thread that actually calls free() That only works when you have infinite memory (or infinite CPU resources). > It's very easy to make a reference counting scheme not stop the world. It's a bit more difficult to make a GC implementation so. Only if by "not stopping the world" you mean your previous suggestion (leaking unbounded amount of memory to free() everyth…

I don't think you understood my point. So let me give you a more concrete example.

The Linux kernel uses RCU to manage data structures that are concurrently read and updated. When an old value (after an update) is no longer needed, a thread can either:

(a) block for a while to make sure no other thread is using it using synchronize_rcu() and then free the memory (see https://www.kernel.org/doc/html/latest/core-api/kernel-api.h...)

(b) if the thread cannot block, it will use call_rcu to register a callback to free the memory at a later time (https://www.kernel.org/doc/html/latest/core-api/kernel-api.h...). That callback generally runs in some other thread to do the cleanup.

Now, moving the concepts to user space, a typical user space implementation will just launch a dedicated thread to free all memory that is no longer needed by any RCU data structures.

Post reply on HN