3 ms·
There are several issues in implementing gc as a library. The first thing a concurrent GC must do to make progress is identify the stack roots. This involves st
by jeffffff 13y ago
There are several issues in implementing gc as a library. The first thing a concurrent GC must do to make progress is identify the stack roots. This involves stopping all the threads and reading their stacks and register values. To stop all the threads safely you have to generate safe points in the code, which requires tight integration with the compiler. The second issue is that in a concurrent mark sweep collector for a language with mutable data (so everthing except haskell) you must put write barriers on all your writes. If you have object A that has been scanned and object B that hasn't been scanned, and you make object A have the only reference to object B, the write barriers will make sure that B is known to be referenced and that the things B references will be scanned. Emitting write barriers as well as their implementation also requires tight coupling between the compiler and the GC. Write barriers can alternatively be implemented with memory protection and signal handlers but usually with a performance penalty.
Generational GC introduces more problems. To be able to only scan the young generation in isolation, you must know either that there are no pointers from the old generation into the young generation or you must know precisely which objects in the young generation are referenced from the old generation. The first is the approach taken by haskell but unfortunately languages with mutable data can't take advantage of that so they must use the second approach, which is implemented with more write barriers (and more compiler-GC coupling).
Copying collectors are generally either stop-the-world or generational/thread local and they run in that thread while collecting. Stop the world again requires safe points but thread local doesn't. You still can't really do the thread local gc in a library because you have to be sure that the compiler isn't keeping pointers only in registers while you scan and you have to emit write barriers to know what's referenced in your thread local generation from older generations.