> why do languages like Crystal and D still use Boehm?
Languages use Boehm for exactly one reason: it is easy to shim into an otherwise manual memory system (it was designed for use in C/C++). I mean no respect to its authors, but using Boehm in production is the worst of all worlds: slow allocations (free list allocator), poor cache locality, and not precise (so you can expect memory leaks). If you are going to do a GC language you want: 1) precise 2) bump allocator 3) compacting collector 4) generations. Essentially you want to allocate fast, only touch live objects (most objects die young), compact them for locality, and only process objects each cycle of similar age. There is a huge amount of engineering that goes into a state of the art collector, but those are the basics.
This is all true but is a somewhat Java-flavoured perspective i.e. generations ties you into a moving collector, which ties you into barriers and complicates FFI, which is not always the right tradeoff.
A non-fragmenting allocator goes a long way to alleviating the need for compactions too.
Not necessarily Java-flavored, but internally vs externally focused, yes. More difficult FFI assuming that is the exception not the rule, and that the language itself takes precedence. Write barriers are also not a given if using segmented heaps. Many ways to do this and no single right way. Memory allocation scheme isn't something that is just bolted on, but needs to be aligned to the rest of the language. For example, Java needs such fast allocations and good GC because it does almost no inline allocation whatsoever, so without the best GC on the planet, it would be a lot slower than it is. Contrast this with Go, which has a solid amount of inline allocations, and hence, can get by with a much slower allocator (~3-4x slower by my measurements) and a more basic mark-sweep allocator since the memory pressure is solidly less.
Languages use Boehm for exactly one reason: it is easy to shim into an otherwise manual memory system (it was designed for use in C/C++). I mean no respect to its authors, but using Boehm in production is the worst of all worlds: slow allocations (free list allocator), poor cache locality, and not precise (so you can expect memory leaks). If you are going to do a GC language you want: 1) precise 2) bump allocator 3) compacting collector 4) generations. Essentially you want to allocate fast, only touch live objects (most objects die young), compact them for locality, and only process objects each cycle of similar age. There is a huge amount of engineering that goes into a state of the art collector, but those are the basics.