As Ron Pressler (pron here on HN) has been emphasising recently, [0] the 'sweep' phase of a moving garbage collector is unaffected by the size or number of dead objects in the heap (at least in the typical case, where there are no finalizers). This isn't the case here though (it uses free lists), or in any C++ GC.
The policy of running all destructors on the same thread doesn't really seem like 'high performance' architecture either, even if there are good reasons for it.
Still a neat project though. I rather like this:
> Oilpan uses a Clang plugin that statically verifies, among many other things, that no heap objects are accessed during destruction of an object
I'm not sure I understand this:
> Oilpan is a garbage collector written in C++ for managing C++ memory that can be connected to V8 using cross-component tracing that treats the tangled C++/JavaScript object graph as one heap.
In what sense are they treated as one heap? How can they be, given that V8 uses a moving GC for its JavaScript heap? Does it just mean there's some mechanism for a C++ object to refer to a JavaScript object, and vice versa?
[0] https://youtu.be/xr73mR7ii9M?t=1081 Principles of Memory Management in Java, September 2026
There's a dead comment below that I vouched that goes into some detail: https://news.ycombinator.com/item?id=49709739
Essentially yes, C++ objects can refer to JS objects and vice-versa, but they don't share a heap, since, as you noted, the V8 JS heap uses a moving collector. They pass the Tracer object back and forth between the JS heap and C++ heap during GC.
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.
This is documented by one of the authors, Don Syme of F#'s fame, on his blog posts and the F# HOPL paper.
Meanwhile Java went through Pizza and other alternative proposals until landing were it did.
However from my point of view both ecosystems could have been much better on version 1.0, had they taken the learnings from Cedar, Modula-3, Eiffel, Sather and Oberon, among other predecessors, regarding AOT compilation and value types, in GC enabled languages.
Conversely, if you language (e.g. LISP) does create a huge amount of GC-pressure, it will lead to the development of the absolute best of GC technology.
Edit: no need to downvote this, it won't change the fact that both GC itself and generational GC in particular was invented specifically to make it possible to run LISP programs on the actual existing hardware in reasonable time.
Oilpan manages DOM nodes in Chromium. Some webapps running on POS terminals like to create and destroy thousands of them very rapidly (I’ve seen such code generated by some Java->JS transpiler used by a customer). On lower-end devices this leads to long GC pauses (10-90s) blocking all interaction. This GC is a joke for the purpose it is being used, where the heap pressure is controlled from JS code from a webapp. A generational GC would have no problems with that. Seeing Oilpan described as “high-performance” in Google docs always makes me laugh, having profiled it for some customers in the past, who were having problems with it.
Also co-routines with it's under the hood management of coroutine stack probably would've complicated GC support even more...
At the time the two main customers of having a C++ GC would be Unreal C++ and C++/CLI, the design that landed on the standard serves neither of them, thus no one adopted it.
Writing extensions for a GC'd language is painful or you let your interop code live in a GC world, I'm pretty sure you more or less always end up with the latter unless you add a way for the hosted language to support some way to control the host language (like JS code "understanding" std::shared_ptr's but that probably adds other securiy risks in terms of low-level exposure).
It's an engineering tradeoff, if you're 100% C++ you don't need that.
GC is another runtime dependency (or a really complex intrusive addition to your code), so if you don't absolutely need it I would avoid it in C++. A lot of C++ programs can avoid it with careful design.
If you need a better GC anyway, in the real world modern GC algorithms are likely more performant for your use case than shared_ptr. Thus shared_ptr should be thought of as the C++ answer only because a "real" GC is hard to implement, but if you implement a real GC anywhere just use it to replace shared_ptr as well. (I lean to use unique_ptr even when GC is available, but I reserve the right to change my mind if someone presents evidence)
If JS points to a C++ DOM node, and that C++ node holds a JS event listener, standard ref-counting leaks instantly.
They don't share memory pages (V8 moves objects, Oilpan C++ is pinned). They just pass the tracer back and forth: V8 marks JS -> hits a C++ wrapper -> hands off to Oilpan -> Oilpan traces C++ -> hands JS refs back to V8.
Comparing it to the JVM misses the point. You can't run a moving GC on massive C++ codebases. Oilpan is just there to end the nightmare of UAFs and manual cycle-breaking.
Wrote a bit more in the sibling comment to pjmpl.
Having written a bunch of more or less complete GC based runtimes, the boundary between C++ code and runtime code is often painful mostly due to GC tracking and reading the article I can only concur with what they're doing with Oilpan for V8/Chrome.
Having had a way in C++ to interrogate the current stack and then trace objects (via C++26 reflections) would've sufficed and probably alleviated the need for a separate GC.
Which is why I became kind of vocal regarding existing practice, or at least preview for community feedback, as there are already several examples of stuff landing into the standard that were not properly baked to start with.