I think it's a good thing to separate requirements/problems/etc.
1: Java has an horrendeous amount of unnecessary garbage due to their erasing generic design (until Valhalla ever arrives), there was some old blog post that chronicled the creation of Dictionary for C#'s System.Collections.Generic (as opposed to the initial Java-like System.Collections) and how it reduced garbage-load by an magnitude.
Java chose compatibility (code continued running as before, with the added compiler checked type safety), so you could use the same Vector, List,etc classes but it also means a ton of boxed Integer,etc objects.
C# went for proper runtime generics, packable struct:s and deprecated their initial collection classes. C++ code with templates can similarly benefit from developer controlled memory usage in places.
You don't need the absolute best GC's when your language doesn't create the same amount of GC-pressure.
2: While the compaction of objects has benefits in compactation and later runtime it does add complications everywhere (you either need to halt while updating moving pointers or have read-barriers).
3: C++ collectors are tricky to get right since compilers don't support it (I'm a bit miffed that they didn't see the GC support through and now removed it), personally I dislike that Boehm has taken so much mindshare since it's lacking in many respects and has given GC's a bad reputation. Reading this article I think it fulfills most parts well (even if it's not 100% faitful to the "abstract" C++ model even if it's probably fine in practice).
4: Reading the article I'm also surprised by the usage of plain pointers, a wrapped pointer type could've provided some concurrent marking support also (assuming optimizing compilers doesn't mess it up), some older GC or other PLang papers measured a 10:1 memory read/write ratio of real world code, so write barriers (esp if only for reference) often aren't that expensive if you're gunning for better latency via concurrent marking.
5: JS <-> C++ is probably the biggest reason they've created their own GC, early JS engines (IE6 iirc) often did reference-counting in C++ and JS GC's and could end up with reference cycles forcing JS developers to avoid certain patterns.
Having unified reachbility in the object graph:s avoids these issues since liveness, in terms of managing moving objects in one heap.
Iirc you created JS-GC:reference objects in V8 interfacing code in the past, didn't check the internals but those objects probably registered themselves with the JS GC,either to be update the references or pin those objects temporarily, you need the interface somewhere, and if the GC's can cooperate at the same time it's an improvement overall.