Hacker News new | ask | show | jobs
by neonsunset 752 days ago
What value does isolated heap offer for memory-safe languages?

Task exceptions can simply be handled via try-catch at the desired level. Millions of concurrently handled tasks is not that high of a number for .NET's threadpool. It's one thing among many that is "nothingburger" in .NET ecosystem which somehow ends up being sold as major advantage in other languages (you can see it with other features too - Nest.js as a "major improvement" for back-end, while it just looks like something we had 10 years ago, "structured concurrency" which is simple task interleaving, etc.).

It's a different, lower-level model, but it comes with the fact that you are not locked into particular (even if good) way of doing concurrency in Erlang.

2 comments

Briefly, the tradeoff that Erlang and its independent process heaps model make is that garbage collection (and execution in general) occurs per-process. In practical terms, this means you have lots of little garbage collections and much fewer "large" (think "full OS process heap") collections.

This provides value in a few ways:

- conceptually: it is very simple. i.e., the garbage collection of one process is not logically tied to the garbage collection of another.

- practically: it lends itself well to low-latency operations, where the garbage collection of one process is able to happen concurrently to the the normal operation of another process.

Please note that I am not claiming this model is superior to any other. That is of course situational. I am just trying to be informative.

This is a good post with more information, if you're interested: https://hamidreza-s.github.io/erlang%20garbage%20collection%...

Thanks!
GC determinism is one of the things you get. Another one is non cooperative asynchronous termination.
Pretty much all efficient GC implementations are inherently non-deterministic, even if predictable.

How can this improve predictability of GC impact?

No global GC. Each erlang process does its own GC, and the GC only happens when the process runs out of space (ie. the heap and stack meet).

You can for example configure a process to have enough initial memory so as not to ever run into GC, this is especially useful if you have a process that does a specific task before terminating. Once terminated the entire process memory is reclaimed.

There is no free lunch in software - the tradeoff is binary serialization and/or data copying over simple function calls. The same goes for GC - for efficient GC, it has to come with quite involved state which has additional cost of spawning. At this point, might use bump allocator, or an arena. Either way, Gen0 (it's a generational GC) in .NET acts like one, STW pauses can be sub-millisecond and are pretty much non-issue, given that you don't even need to allocate that often compared to many other high-level languages.