Quick Links:

Releases | Mailing Lists | Source Control | Issue Tracker | Regression Tests

20 Building a Hybrid Collector

Chapter 20
Building a Hybrid Collector

Extend the Tutorial plan to create a ”copy-MS” collector, which allocates into a copying nursery and at collection time, copies nursery survivors into a mark-sweep space. This plan does not require a write barrier (it is not strictly generational, as it will collect the whole heap each time the heap is full). Later we will extended it with a write barrier, allowing the nursery to be collected in isolation. Such a collector would be a generational mark-sweep collector, similar to GenMS.

20.1 Add a Copying Nursery

This step will change your simple collector from using a bump pointer to a free list (but still without any garbage collection).

  1. In TutorialConstraints, make the following changes:
    1. Override the movesObjects() method to return true, reflecting that we are now building a copying collector:
      @Override 
      public boolean movesObjects() { return true; }
    2. Remove the restriction on default alloc bytes (since default allocation will now go to a bump-pointed space). To do this, remove the override of maxNonLOSDefaultAllocBytes().
    3. Add a restriction on the maximum size that may be copied into the (default) non-LOS mature space:
      @Override 
      public int maxNonLOSCopyBytes() { return SegregatedFreeListSpace.MAX_FREELIST_OBJECT_BYTES;}
  2. In Tutorial, add a nursery space:
    1. Create a new space, nurserySpace, of type CopySpace. The new space will initially be a from-space, so provide false as the third argument. Initialize the space with a contiguous virtual memory region consuming 0.15 of the heap by passing ”0.15” and ”true” as arguments to the constructor of VMRequest(more on this later). Create and initialize a new integer constant to hold the descriptor for this new space:
      public static final CopySpace nurserySpace = new CopySpace("nursery", false, VMRequest.highFraction(0.15f)); 
      public static final int NURSERY = nurserySpace.getDescriptor();
    2. Add the necessary import statements
    3. Add nurserySpace to the PREPARE and RELEASE phases of collectionPhase(), prior to the existing calls to msTrace. Pass true to nurserySpace.prepare() indicating that the nursery is a from-space during collection.
    4. Fix accounting so that Tutorial accounts for space consumed by nurserySpace:
      1. Add nurserySpace to the equation in getPagesUsed()
    5. Since initial allocation will be into a copying space, we need to account for copy reserve:
      1. Add a method to override getCollectionReserve() which returns nurserySpace.reservedPages() + super.getCollectionReserve()
      2. Add a method to override getPagesAvail(), returning getTotalPages() - getPagesReserved()) >> 1;

20.2 Add nursery allocation

In TutorialMutator, replace the free-list allocator (MarkSweepLocal) with a nursery allocator: Use an instance of CopyLocal, calling it nursery. The constructor argument should be Tutorial.nurserySpace:

  1. change alloc() to use nursery.alloc() rather than ms.alloc().
  2. remove the call to msSpace.postAlloc() from postAlloc() since there is no special post-allocation work necessary for the new copy space. The call to super.postAlloc() should remain conditional on allocator != Tutorial.ALLOC_DEFAULT.
  3. change the check within getAllocatorFromSpace() to check against Tutorial.nurserySpace and to return nursery.
  4. adjust collectionPhase
    1. replace call to ms.prepare() with nursery.reset()
    2. remove call to ms.release() since there are no actions necessary for the nursery allocator upon release.

20.3 Add copying to the collector

In TutorialCollector add the capacity for the collector to allocate (copy), since our new hybrid collector will perform copying.

  1. Add local allocators for both large object space and the mature space:
    private final LargeObjectLocal los = new LargeObjectLocal(Plan.loSpace); 
    private final MarkSweepLocal mature = new MarkSweepLocal(Tutorial.msSpace);
  2. Add an allocCopy() method that conditionally allocates to the LOS or mature space:
    @Override 
    public final Address allocCopy(ObjectReference original, int bytes, 
                                 int align, int offset, int allocator) { 
      if (allocator == Plan.ALLOC_LOS) 
       return los.alloc(bytes, align, offset); 
      else 
       return mature.alloc(bytes, align, offset); 
    }
  3. Add a postCopy() method that conditionally calls LOS or mature space post-copy actions:
    @Override 
    public final void postCopy(ObjectReference object, ObjectReference typeRef, 
                             int bytes, int allocator) { 
    if (allocator == Plan.ALLOC_LOS) 
      Plan.loSpace.initializeHeader(object, false); 
    else 
      Tutorial.msSpace.postCopy(object, true); 
    }

20.4 Make necessary changes to TutorialTraceLocal

  1. Add nurserySpace clauses to isLive() and traceObject():
    1. Add the following to isLive():
      if (Space.isInSpace(Tutorial.NURSERY, object)) 
        return Tutorial.nurserySpace.isLive(object);
    2. Add the following to traceObject():
      if (Space.isInSpace(Tutorial.NURSERY, object)) 
        return Tutorial.nurserySpace.traceObject(this, object, Tutorial.ALLOC_DEFAULT);
  2. Add a new willNotMoveInCurrentCollection() method, which identifies those objects which do not move (necessary for copying collectors):
    @Override 
    public boolean willNotMoveInCurrentCollection(ObjectReference object) { 
      return !Space.isInSpace(Tutorial.NURSERY, object); 
    }
  3. Modify PlanSpecificConfig to add the new nursery space:
    new PlanSpecific("org.mmtk.plan.tutorial.Tutorial").addExpectedSpaces("ms", "nursery"), "Tutorial");

With these changes, Tutorial should now work. You should be able to again build a BaseBaseTutorial image and test it against any benchmark. Again, if you use -X:gc:verbose=3 you can see the movement of data among the spaces at each garbage collection.