What are approaches to optimize the mark phase of a non-generational GC?

188 views Asked by At

I am running on Unity's Boehm–Demers–Weiser garbage collector, which is a non-generational GC.

I have a large tree of managed objects in memory (~100k objects, ~200MiB allocation).

These objects are essentially a cache and never go out of scope, so they never actually get sweeped by the GC.

However, because Boehm is non-generational, this stale cache never gets moved up to higher generations. This causes the mark phase to take a very high amount of processing time, as it has to traverse this whole cache on every collection, causing noticeable lag spikes.

This is "by-design", as the Unity documentation puts it:

Crucially, Unity’s garbage collection – which uses the Boehm GC algorithm – is non-generational and non-compacting. “Non-generational” means that the GC must sweep through the entire heap when performing a collection pass, and its performance therefore degrades as the heap expands.

I am well aware of approaches to reduce recurring garbage allocation, however I cannot find any information on how to optimize a large, stale, baseline allocation in a non-generational GC.

More specifically:

  • Is there any way to mark a root pointer (e.g. static field) as ignored from GC entirely?
  • Are there some data structure patterns that are faster to traverse in the mark phase?
  • Conversely, are there known data structure patterns that hinder the mark phase speed?

These questions are just some of my hypotheses to solve this, but I'm open to all suggestions.

1

There are 1 answers

3
the8472 On

One could approximate generational behavior by separating program startup with initialization of static data structures from steady state operation. All pointers into the startup memory region could be ignored while pointers from it should not exist since nothing allocated after the switchpoint (which would be under GC control) has been allocated yet.

One could even GC the startup region once before switching to a new region. Essentially you would end up with a limited form of region-based, non-moving collector where references between regions only happen in one direction.