Exemple #1
0
  /**
   * Perform a (global) collection phase.
   *
   * @param phaseId Collection phase to execute.
   */
  @NoInline
  public void collectionPhase(short phaseId) {
    if (phaseId == PREPARE) {
      nurserySpace.prepare(true);
    }

    if (phaseId == RELEASE) {
      nurserySpace.release();
    }

    super.collectionPhase(phaseId);
  }
  /**
   * Perform a (global) collection phase.
   *
   * @param phaseId Collection phase to execute.
   */
  @NoInline
  public void collectionPhase(short phaseId) {
    if (phaseId == SET_COLLECTION_KIND) {
      super.collectionPhase(phaseId);
      gcFullHeap = requiresFullHeapCollection();
      return;
    }

    if (phaseId == PREPARE) {
      nurserySpace.prepare(true);
      if (traceFullHeap()) {
        if (gcFullHeap) {
          if (Stats.gatheringStats()) fullHeap.set();
          fullHeapTime.start();
        }
        super.collectionPhase(phaseId);

        // we can throw away the remsets (but not modbuf) for a full heap GC
        remsetPool.clearDeque(1);
        arrayRemsetPool.clearDeque(2);
      }
      return;
    }

    if (phaseId == CLOSURE) {
      if (!traceFullHeap()) {
        nurseryTrace.prepare();
      }
      return;
    }

    if (phaseId == RELEASE) {
      nurserySpace.release();
      modbufPool.clearDeque(1);
      remsetPool.clearDeque(1);
      arrayRemsetPool.clearDeque(2);
      if (!traceFullHeap()) {
        nurseryTrace.release();
      } else {
        super.collectionPhase(phaseId);
        if (gcFullHeap) fullHeapTime.stop();
      }
      nextGCFullHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
      return;
    }

    super.collectionPhase(phaseId);
  }
Exemple #3
0
 /**
  * Perform any post-copy actions. In this case nothing is required.
  *
  * @param object The newly allocated object
  * @param typeRef the type reference for the instance being created
  * @param bytes The size of the space to be allocated (in bytes)
  */
 @Inline
 public final void postCopy(
     ObjectReference object, ObjectReference typeRef, int bytes, int allocator) {
   CopySpace.clearGCBits(object);
   RCHeader.initializeHeader(object, typeRef, false);
   RCHeader.makeUnlogged(object);
   ExplicitFreeListSpace.unsyncSetLiveBit(object);
 }
Exemple #4
0
  /**
   * This method controls the triggering of a GC. It is called periodically during allocation.
   * Returns true to trigger a collection.
   *
   * @param spaceFull Space request failed, must recover pages within 'space'.
   * @return True if a collection is requested by the plan.
   */
  public final boolean collectionRequired(boolean spaceFull) {
    int nurseryPages = nurserySpace.reservedPages();

    if (nurseryPages > Options.nurserySize.getMaxNursery()) {
      return true;
    }

    if (virtualMemoryExhausted()) return true;

    return super.collectionRequired(spaceFull);
  }
Exemple #5
0
  /**
   * Determine if this GC should be a full heap collection.
   *
   * @return True is this GC should be a full heap collection.
   */
  protected boolean requiresFullHeapCollection() {
    if (collectionTrigger == Collection.EXTERNAL_GC_TRIGGER
        && Options.fullHeapSystemGC.getValue()) {
      return true;
    }

    if (nextGCFullHeap || collectionAttempt > 1) {
      // Forces full heap collection
      return true;
    }

    if (loSpace.allocationFailed()
        || nonMovingSpace.allocationFailed()
        || (USE_CODE_SPACE
            && (largeCodeSpace.allocationFailed() || smallCodeSpace.allocationFailed()))) {
      // We need space from the nursery
      return true;
    }

    if (virtualMemoryExhausted()) return true;

    int smallNurseryPages = nurserySpace.committedPages();
    int smallNurseryYield = (int) ((smallNurseryPages << 1) * SURVIVAL_ESTIMATE);

    if (smallNurseryYield < getPagesRequired()) {
      // Our total yield is insufficent.
      return true;
    }

    if (nurserySpace.allocationFailed()) {
      if (smallNurseryYield < (nurserySpace.requiredPages() << 1)) {
        // We have run out of VM pages in the nursery
        return true;
      }
    }

    return false;
  }
  /**
   * This method controls the triggering of a GC. It is called periodically during allocation.
   * Returns true to trigger a collection.
   *
   * @param spaceFull Space request failed, must recover pages within 'space'.
   * @return True if a collection is requested by the plan.
   */
  public final boolean collectionRequired(boolean spaceFull, Space space) {
    int nurseryPages = nurserySpace.reservedPages();

    if (nurseryPages > Options.nurserySize.getMaxNursery()) {
      return true;
    }

    if (virtualMemoryExhausted()) {
      return true;
    }

    if (spaceFull && space != nurserySpace) {
      nextGCFullHeap = true;
    }

    return super.collectionRequired(spaceFull, space);
  }
Exemple #7
0
/**
 * This abstract class implements the core functionality of generic two-generationa copying
 * collectors. Nursery collections occur when either the heap is full or the nursery is full. The
 * nursery size is determined by an optional command line argument. If undefined, the nursery size
 * is "infinite", so nursery collections only occur when the heap is full (this is known as a
 * flexible-sized nursery collector). Thus both fixed and flexible nursery sizes are supported. Full
 * heap collections occur when the nursery size has dropped to a statically defined threshold,
 * <code>NURSERY_THRESHOLD</code>
 *
 * <p>See also Plan.java for general comments on local vs global plan classes.
 */
@Uninterruptible
public abstract class Gen extends StopTheWorld {

  /**
   * ***************************************************************************
   *
   * <p>Constants
   */
  protected static final float SURVIVAL_ESTIMATE = 0.8f; // est yield

  protected static final float MATURE_FRACTION = 0.5f; // est yield
  private static final float WORST_CASE_COPY_EXPANSION =
      1.5f; // worst case for addition of one word overhead due to address based hashing
  public static final boolean IGNORE_REMSETS = false;
  public static final boolean USE_NON_HEAP_OBJECT_REFERENCE_WRITE_BARRIER = true;
  public static final boolean USE_OBJECT_BARRIER_FOR_AASTORE =
      false; // choose between slot and object barriers
  public static final boolean USE_OBJECT_BARRIER_FOR_PUTFIELD =
      false; // choose between slot and object barriers
  public static final boolean USE_OBJECT_BARRIER =
      USE_OBJECT_BARRIER_FOR_AASTORE || USE_OBJECT_BARRIER_FOR_PUTFIELD;

  /** Fraction of available virtual memory to give to the nursery (if contiguous) */
  protected static final float NURSERY_VM_FRACTION = 0.15f;

  /** Switch between a contiguous and discontiguous nursery (experimental) */
  static final boolean USE_DISCONTIGUOUS_NURSERY = false;

  // Allocators
  public static final int ALLOC_NURSERY = ALLOC_DEFAULT;
  public static final int ALLOC_MATURE = StopTheWorld.ALLOCATORS + 1;
  public static final int ALLOC_MATURE_MINORGC = StopTheWorld.ALLOCATORS + 2;
  public static final int ALLOC_MATURE_MAJORGC = StopTheWorld.ALLOCATORS + 3;

  public static final int SCAN_NURSERY = 0;
  public static final int SCAN_MATURE = 1;

  /**
   * ***************************************************************************
   *
   * <p>Class fields
   */

  /* Statistics */
  protected static final BooleanCounter fullHeap = new BooleanCounter("majorGC", true, true);

  private static final Timer fullHeapTime = new Timer("majorGCTime", false, true);
  protected static final EventCounter wbFast;
  protected static final EventCounter wbSlow;
  public static final SizeCounter nurseryMark;
  public static final SizeCounter nurseryCons;

  /** The nursery space is where all new objects are allocated by default */
  private static final VMRequest vmRequest =
      USE_DISCONTIGUOUS_NURSERY ? VMRequest.create() : VMRequest.create(NURSERY_VM_FRACTION, true);

  public static final CopySpace nurserySpace =
      new CopySpace("nursery", DEFAULT_POLL_FREQUENCY, false, vmRequest);

  public static final int NURSERY = nurserySpace.getDescriptor();
  private static final Address NURSERY_START = nurserySpace.getStart();

  /**
   * ***************************************************************************
   *
   * <p>Instance fields
   */
  /* status fields */
  public boolean gcFullHeap = false;

  public boolean nextGCFullHeap = false;

  /* The trace object */
  public final Trace nurseryTrace = new Trace(metaDataSpace);

  /** Remset pools */
  public final SharedDeque modbufPool = new SharedDeque("modBufs", metaDataSpace, 1);

  public final SharedDeque remsetPool = new SharedDeque("remSets", metaDataSpace, 1);
  public final SharedDeque arrayRemsetPool = new SharedDeque("arrayRemSets", metaDataSpace, 2);

  /*
   * Class initializer
   */
  static {
    if (GATHER_WRITE_BARRIER_STATS) {
      wbFast = new EventCounter("wbFast");
      wbSlow = new EventCounter("wbSlow");
    } else {
      wbFast = null;
      wbSlow = null;
    }
    if (Stats.GATHER_MARK_CONS_STATS) {
      nurseryMark = new SizeCounter("nurseryMark", true, true);
      nurseryCons = new SizeCounter("nurseryCons", true, true);
    } else {
      nurseryMark = null;
      nurseryCons = null;
    }
  }

  /**
   * ***************************************************************************
   *
   * <p>Collection
   */

  /** Force the next collection to be full heap. */
  public void forceFullHeapCollection() {
    nextGCFullHeap = true;
  }

  /**
   * Perform a (global) collection phase.
   *
   * @param phaseId Collection phase to execute.
   */
  @NoInline
  public void collectionPhase(short phaseId) {
    if (phaseId == SET_COLLECTION_KIND) {
      super.collectionPhase(phaseId);
      gcFullHeap = requiresFullHeapCollection();
      return;
    }

    if (phaseId == PREPARE) {
      nurserySpace.prepare(true);
      if (traceFullHeap()) {
        if (gcFullHeap) {
          if (Stats.gatheringStats()) fullHeap.set();
          fullHeapTime.start();
        }
        super.collectionPhase(phaseId);

        // we can throw away the remsets (but not modbuf) for a full heap GC
        remsetPool.clearDeque(1);
        arrayRemsetPool.clearDeque(2);
      }
      return;
    }

    if (phaseId == CLOSURE) {
      if (!traceFullHeap()) {
        nurseryTrace.prepare();
      }
      return;
    }
    if (phaseId == RELEASE) {
      nurserySpace.release();
      modbufPool.clearDeque(1);
      remsetPool.clearDeque(1);
      arrayRemsetPool.clearDeque(2);
      if (!traceFullHeap()) {
        nurseryTrace.release();
      } else {
        super.collectionPhase(phaseId);
        if (gcFullHeap) fullHeapTime.stop();
      }
      nextGCFullHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
      return;
    }

    super.collectionPhase(phaseId);
  }

  /**
   * This method controls the triggering of a GC. It is called periodically during allocation.
   * Returns true to trigger a collection.
   *
   * @param spaceFull Space request failed, must recover pages within 'space'.
   * @return True if a collection is requested by the plan.
   */
  public final boolean collectionRequired(boolean spaceFull) {
    int nurseryPages = nurserySpace.reservedPages();

    if (nurseryPages > Options.nurserySize.getMaxNursery()) {
      return true;
    }

    if (virtualMemoryExhausted()) return true;

    return super.collectionRequired(spaceFull);
  }

  /**
   * Determine if this GC should be a full heap collection.
   *
   * @return True is this GC should be a full heap collection.
   */
  protected boolean requiresFullHeapCollection() {
    if (collectionTrigger == Collection.EXTERNAL_GC_TRIGGER
        && Options.fullHeapSystemGC.getValue()) {
      return true;
    }

    if (nextGCFullHeap || collectionAttempt > 1) {
      // Forces full heap collection
      return true;
    }

    if (loSpace.allocationFailed()
        || nonMovingSpace.allocationFailed()
        || (USE_CODE_SPACE
            && (largeCodeSpace.allocationFailed() || smallCodeSpace.allocationFailed()))) {
      // We need space from the nursery
      return true;
    }

    if (virtualMemoryExhausted()) return true;

    int smallNurseryPages = nurserySpace.committedPages();
    int smallNurseryYield = (int) ((smallNurseryPages << 1) * SURVIVAL_ESTIMATE);

    if (smallNurseryYield < getPagesRequired()) {
      // Our total yield is insufficent.
      return true;
    }

    if (nurserySpace.allocationFailed()) {
      if (smallNurseryYield < (nurserySpace.requiredPages() << 1)) {
        // We have run out of VM pages in the nursery
        return true;
      }
    }

    return false;
  }

  /**
   * Independent of how many pages remain in the page budget (a function of heap size), we must
   * ensure we never exhaust virtual memory. Therefore we must never let the nursery grow to the
   * extent that it can't be copied into the mature space.
   *
   * @return True if the nursery has grown to the extent that it may not be able to be copied into
   *     the mature space.
   */
  private boolean virtualMemoryExhausted() {
    return ((int) (nurserySpace.reservedPages() * WORST_CASE_COPY_EXPANSION)
        >= getMaturePhysicalPagesAvail());
  }

  /**
   * ***************************************************************************
   *
   * <p>Correctness
   */

  /**
   * ***************************************************************************
   *
   * <p>Accounting
   */

  /**
   * Return the number of pages in use given the pending allocation. Simply add the nursery's
   * contribution to that of the superclass.
   *
   * @return The number of pages reserved given the pending allocation, excluding space reserved for
   *     copying.
   */
  @Override
  public int getPagesUsed() {
    return (nurserySpace.reservedPages() + super.getPagesUsed());
  }

  /**
   * Return the number of pages available for allocation, <i>assuming all future allocation is to
   * the nursery</i>.
   *
   * @return The number of pages available for allocation, <i>assuming all future allocation is to
   *     the nursery</i>.
   */
  @Override
  public int getPagesAvail() {
    return super.getPagesAvail() >> 1;
  }

  /**
   * Return the number of pages reserved for copying.
   *
   * @return The number of pages reserved given the pending allocation, including space reserved for
   *     copying.
   */
  @Override
  public int getCollectionReserve() {
    return nurserySpace.reservedPages() + super.getCollectionReserve();
  }

  /**
   * Return the number of pages available for allocation into the mature space.
   *
   * @return The number of pages available for allocation into the mature space.
   */
  public abstract int getMaturePhysicalPagesAvail();

  /**
   * Calculate the number of pages a collection is required to free to satisfy outstanding
   * allocation requests.
   *
   * @return the number of pages a collection is required to free to satisfy outstanding allocation
   *     requests.
   */
  @Override
  public int getPagesRequired() {
    /* We don't currently pretenure, so mature space must be zero */
    return super.getPagesRequired() + (nurserySpace.requiredPages() << 1);
  }

  /**
   * ***************************************************************************
   *
   * <p>Miscellaneous
   */

  /**
   * Return true if the address resides within the nursery
   *
   * @param addr The object to be tested
   * @return true if the address resides within the nursery
   */
  @Inline
  static boolean inNursery(Address addr) {
    if (USE_DISCONTIGUOUS_NURSERY) return Map.getDescriptorForAddress(addr) == NURSERY;
    else return addr.GE(NURSERY_START);
  }

  /**
   * Return true if the object resides within the nursery
   *
   * @param obj The object to be tested
   * @return true if the object resides within the nursery
   */
  @Inline
  static boolean inNursery(ObjectReference obj) {
    return inNursery(obj.toAddress());
  }

  /** @return Does the mature space do copying ? */
  protected boolean copyMature() {
    return false;
  }

  /**
   * Print pre-collection statistics. In this class we prefix the output indicating whether the
   * collection was full heap or not.
   */
  public void printPreStats() {
    if ((Options.verbose.getValue() >= 1) && (gcFullHeap)) Log.write("[Full heap]");
    super.printPreStats();
  }

  /** @return The mature space, set by each subclass of <code>Gen</code>. */
  protected abstract Space activeMatureSpace();

  /**
   * @return True if we should trace the whole heap during collection. True if we're ignorning
   *     remsets or if we're doing a full heap GC.
   */
  public final boolean traceFullHeap() {
    return IGNORE_REMSETS || gcFullHeap;
  }

  /** @return Is current GC only collecting objects allocated since last GC. */
  public final boolean isCurrentGCNursery() {
    return !gcFullHeap;
  }

  /** @return Is last GC a full collection? */
  public final boolean lastCollectionFullHeap() {
    return gcFullHeap;
  }

  /**
   * @see org.mmtk.plan.Plan#willNeverMove
   * @param object Object in question
   * @return True if the object will never move
   */
  @Override
  public boolean willNeverMove(ObjectReference object) {
    if (Space.isInSpace(NURSERY, object)) return false;
    return super.willNeverMove(object);
  }

  /**
   * Return the expected reference count. For non-reference counting collectors this becomes a
   * true/false relationship.
   *
   * @param object The object to check.
   * @param sanityRootRC The number of root references to the object.
   * @return The expected (root excluded) reference count.
   */
  public int sanityExpectedRC(ObjectReference object, int sanityRootRC) {
    Space space = Space.getSpaceForObject(object);

    // Nursery
    if (space == Gen.nurserySpace) {
      return SanityChecker.DEAD;
    }

    // Immortal spaces
    if (space == Gen.immortalSpace || space == Gen.vmSpace) {
      return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD;
    }

    // Mature space (nursery collection)
    if (VM.activePlan.global().isCurrentGCNursery()) {
      return SanityChecker.UNSURE;
    }

    // Mature space (full heap collection)
    return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD;
  }

  /** Register specialized methods. */
  @Interruptible
  protected void registerSpecializedMethods() {
    TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, GenNurseryTraceLocal.class);
    super.registerSpecializedMethods();
  }
}
Exemple #8
0
 /**
  * Calculate the number of pages a collection is required to free to satisfy outstanding
  * allocation requests.
  *
  * @return the number of pages a collection is required to free to satisfy outstanding allocation
  *     requests.
  */
 @Override
 public int getPagesRequired() {
   /* We don't currently pretenure, so mature space must be zero */
   return super.getPagesRequired() + (nurserySpace.requiredPages() << 1);
 }
Exemple #9
0
 /**
  * Return the number of pages reserved for copying.
  *
  * @return The number of pages reserved given the pending allocation, including space reserved for
  *     copying.
  */
 @Override
 public int getCollectionReserve() {
   return nurserySpace.reservedPages() + super.getCollectionReserve();
 }
Exemple #10
0
 /**
  * Return the number of pages in use given the pending allocation. Simply add the nursery's
  * contribution to that of the superclass.
  *
  * @return The number of pages reserved given the pending allocation, excluding space reserved for
  *     copying.
  */
 @Override
 public int getPagesUsed() {
   return (nurserySpace.reservedPages() + super.getPagesUsed());
 }
Exemple #11
0
 /**
  * Independent of how many pages remain in the page budget (a function of heap size), we must
  * ensure we never exhaust virtual memory. Therefore we must never let the nursery grow to the
  * extent that it can't be copied into the mature space.
  *
  * @return True if the nursery has grown to the extent that it may not be able to be copied into
  *     the mature space.
  */
 private boolean virtualMemoryExhausted() {
   return ((int) (nurserySpace.reservedPages() * WORST_CASE_COPY_EXPANSION)
       >= getMaturePhysicalPagesAvail());
 }
Exemple #12
0
  /**
   * This method controls the triggering of a GC. It is called periodically during allocation.
   * Returns true to trigger a collection.
   *
   * @param spaceFull Space request failed, must recover pages within 'space'.
   * @return True if a collection is requested by the plan.
   */
  public final boolean collectionRequired(boolean spaceFull) {
    boolean nurseryFull = nurserySpace.reservedPages() > Options.nurserySize.getMaxNursery();

    return super.collectionRequired(spaceFull) || nurseryFull;
  }
Exemple #13
0
/**
 * This class implements the global state of a simple reference counting collector.
 *
 * <p>All plans make a clear distinction between <i>global</i> and <i>thread-local</i> activities,
 * and divides global and local state into separate class hierarchies. Global activities must be
 * synchronized, whereas no synchronization is required for thread-local activities. There is a
 * single instance of Plan (or the appropriate sub-class), and a 1:1 mapping of PlanLocal to "kernel
 * threads" (aka CPUs or in Jikes RVM, Processors). Thus instance methods of PlanLocal allow fast,
 * unsychronized access to functions such as allocation and collection.
 *
 * <p>The global instance defines and manages static resources (such as memory and virtual memory
 * resources). This mapping of threads to instances is crucial to understanding the correctness and
 * performance properties of MMTk plans.
 */
@Uninterruptible
public class GenRC extends RCBase {

  /**
   * **************************************************************************
   *
   * <p>Class variables
   */

  /** The nursery space, where all new objects are allocated by default. */
  public static CopySpace nurserySpace =
      new CopySpace("nursery", DEFAULT_POLL_FREQUENCY, false, VMRequest.create(0.15f, true));

  public static final int NS = nurserySpace.getDescriptor();

  // Allocators
  public static final int ALLOC_NURSERY = ALLOC_DEFAULT;

  /**
   * ************************************************************************** Instance variables
   */

  /** Constructor. */
  public GenRC() {
    if (VM.VERIFY_ASSERTIONS) {
      VM.assertions._assert(WITH_COALESCING_RC);
    }
  }

  /**
   * ***************************************************************************
   *
   * <p>Collection
   */

  /**
   * Perform a (global) collection phase.
   *
   * @param phaseId Collection phase to execute.
   */
  @NoInline
  public void collectionPhase(short phaseId) {
    if (phaseId == PREPARE) {
      nurserySpace.prepare(true);
    }

    if (phaseId == RELEASE) {
      nurserySpace.release();
    }

    super.collectionPhase(phaseId);
  }

  /**
   * This method controls the triggering of a GC. It is called periodically during allocation.
   * Returns true to trigger a collection.
   *
   * @param spaceFull Space request failed, must recover pages within 'space'.
   * @return True if a collection is requested by the plan.
   */
  public final boolean collectionRequired(boolean spaceFull) {
    boolean nurseryFull = nurserySpace.reservedPages() > Options.nurserySize.getMaxNursery();

    return super.collectionRequired(spaceFull) || nurseryFull;
  }

  /**
   * Return the number of pages available for allocation, <i>assuming all future allocation is to
   * the nursery</i>.
   *
   * @return The number of pages available for allocation, <i>assuming all future allocation is to
   *     the nursery</i>.
   */
  public int getPagesAvail() {
    return super.getPagesAvail() >> 1;
  }

  /**
   * Return the number of pages reserved for copying.
   *
   * @return The number of pages reserved given the pending allocation, including space reserved for
   *     copying.
   */
  public final int getCollectionReserve() {
    return nurserySpace.reservedPages() + super.getCollectionReserve();
  }

  /**
   * Return the number of pages in use given the pending allocation. Simply add the nursery's
   * contribution to that of the superclass.
   *
   * @return The number of pages reserved given the pending allocation, excluding space reserved for
   *     copying.
   */
  public final int getPagesUsed() {
    return super.getPagesUsed() + nurserySpace.reservedPages();
  }

  /**
   * Calculate the number of pages a collection is required to free to satisfy outstanding
   * allocation requests.
   *
   * @return the number of pages a collection is required to free to satisfy outstanding allocation
   *     requests.
   */
  public int getPagesRequired() {
    return super.getPagesRequired() + (nurserySpace.requiredPages() << 1);
  }

  /**
   * @see org.mmtk.plan.Plan#willNeverMove
   * @param object Object in question
   * @return True if the object will never move
   */
  @Override
  public boolean willNeverMove(ObjectReference object) {
    if (Space.isInSpace(NS, object)) return false;
    return super.willNeverMove(object);
  }
}
Exemple #14
0
 /**
  * Calculate the number of pages a collection is required to free to satisfy outstanding
  * allocation requests.
  *
  * @return the number of pages a collection is required to free to satisfy outstanding allocation
  *     requests.
  */
 public int getPagesRequired() {
   return super.getPagesRequired() + (nurserySpace.requiredPages() << 1);
 }
Exemple #15
0
 /**
  * Return the number of pages in use given the pending allocation. Simply add the nursery's
  * contribution to that of the superclass.
  *
  * @return The number of pages reserved given the pending allocation, excluding space reserved for
  *     copying.
  */
 public final int getPagesUsed() {
   return super.getPagesUsed() + nurserySpace.reservedPages();
 }
Exemple #16
0
 /**
  * Return the number of pages reserved for copying.
  *
  * @return The number of pages reserved given the pending allocation, including space reserved for
  *     copying.
  */
 public final int getCollectionReserve() {
   return nurserySpace.reservedPages() + super.getCollectionReserve();
 }