// HACKER NEWS — CYBERSECURITY
High-performance garbage collection for C++
Published 26 May 2020 · Tagged with internals memory cppgc
In the past we have already been writing about garbage collection for JavaScript, the document object model (DOM), and how all of this is implemented and optimized in V8. Not everything in Chromium is JavaScript though, as most of the browser and its Blink rendering engine where V8 is embedded are written in C++. JavaScript can be used to interact with the DOM that is then processed by the rendering pipeline.
Because the C++ object graph around the DOM is heavily tangled with Javascript objects, the Chromium team switched a couple of years ago to a garbage collector, called Oilpan, for managing this kind of memory. 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.
This post is the first in a series of Oilpan blog posts which will provide an overview of the core principles of Oilpan and its C++ APIs. For this post we will cover some of the supported features, explain how they interact with various subsystems of the garbage collector, and do a deep dive into concurrently reclaiming objects in the sweeper.
Most excitingly, Oilpan is currently implemented in Blink but moving to V8 in the form of a garbage collection library. The goal is to make C++ garbage collection easily available for all V8 embedders and more C++ developers in general.
Oilpan implements a Mark-Sweep garbage collector where garbage collection is split among two phases: marking where the managed heap is scanned for live objects, and sweeping where dead objects on the managed heap are reclaimed.
We’ve covered the basics of marking already when introducing concurrent marking in V8. To recap, scanning all objects for live ones can be seen as graph traversal where objects are nodes and pointers between objects are edges. Traversal starts at roots which are registers, native execution stack (which we will call stack from now on), and other globals, as described here.
C++ is not different to JavaScript in that aspect. In contrast to JavaScript though, C++ objects are statically typed and thus cannot change their representation at runtime. C++ objects managed using Oilpan leverage this fact and provide a description of pointers to other objects (edges in the graph) via visitor pattern. The basic pattern for describing Oilpan objects is the following:
In the example above, LinkedNode is managed by Oilpan as indicated by inheriting from GarbageCollected. When the garbage collector processes an object it discovers outgoing pointers by invoking the Trace method of the object. The type Member is a smart pointer that is syntactically similar to e.g. std::shared_ptr, which is provided by Oilpan and used to maintain a consistent state while traversing the graph during marking. All of this allows Oilpan to precisely know where pointers reside in its managed objects.
Avid readers probably noticed and may be scared that first_node and second_node are kept as raw C++ pointers on the stack in the example above. Oilpan does not add abstractions for working with the stack, relying solely on conservative stack scanning to find pointers into its managed heap when processing roots. This works by iterating the stack word-by-word and interpreting those words as pointers into the managed heap. This means that Oilpan does not impose a performance penalty for accessing stack-allocated objects. Instead, it moves the cost to the garbage collection time where it scans the stack conservatively. Oilpan as integrated in the renderer tries to delay garbage collection until it reaches a state where it’s guaranteed to have no interesting stack. Since the web is event based and execution is driven by processing tasks in event loops, such opportunities are plentiful.