top | item 41523962

(no title)

davisp | 1 year ago

Also, for anyone not completely familiar with Erlang's terminology, the translation of "per process garbage collection" to Go would be "per goroutine garbage collection". As mentioned in a sibling comment, this allows Erlang style garbage collection to avoid pausing the entire operating system process when running garbage collectin.

discuss

order

whizzter|1 year ago

Per-process GC is an optimization similar to nurseries in regular collectors, esp any object that has been sent in a message must be visible globally (yes there could be small object optimizations but that would increase sender complexity).

Also an overlooked part here is that the global Erlang GC is easier to parallellize and/or keep incremental since it won't have object cycles sans PID's (that probably have special handling anyhow).

TlDr; GC's become way harder as soon as you have cyclic objects, Erlang avoids it and thus parts of it being good is more about Erlang being "simple".

toast0|1 year ago

Erlang avoids object cycles because it's impossible to make an old term point to a new one; data is immutable, so new terms can only referenece previous terms. This means the GC doesn't have to consider cycles and keeps things simple.

But that's separate from per process GC. Per process GC is possible because processes don't share memory[1], so each process can compact its own memory without coordination with other processes. GC becomes stop the process, not stop the world, and it's effectively preemptable, so one process doing a lot of GC will not block other processes from getting cpu time.

Also, per process GC enables a pattern where a well tuned short lived process is spawned to do some work, then die, and all its garbage can be thrown away without a complex collection. With shared GC, it can be harder to avoid the impact of short lived tasks on the overall system.

[1] yes yes, shared refcounted binaries, which are allocated separately from process memory.

neonsunset|1 year ago

> GC's become way harder as soon as you have cyclic objects

This may be true only for some implementations. Good GC implementations operate on the concept of object graph roots. Whether the graph has cyclic references or not is irrelevant as the GC scans the relevant memory linearly. As long as the graph is unrooted, such GC implementations are able to still easily collect it (or, to be more precise, ignore it - the generational moving GCs the cost is the live objects that need to be relocated to an older/tenured generation).

hinkley|1 year ago

Erlang is much more likely for GC overhead to grow sub-linearly, because more logic means more isolates (processes) rather than more state, more deeply nested, in the existing processes. Say at the square root of total data.