001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.mmtk.plan.generational; 014 015 import org.mmtk.plan.*; 016 import org.mmtk.policy.CopySpace; 017 import org.mmtk.policy.Space; 018 019 import org.mmtk.utility.deque.*; 020 import org.mmtk.utility.heap.Map; 021 import org.mmtk.utility.heap.VMRequest; 022 import org.mmtk.utility.Log; 023 import org.mmtk.utility.options.Options; 024 import org.mmtk.utility.sanitychecker.SanityChecker; 025 import org.mmtk.utility.statistics.*; 026 027 import org.mmtk.vm.VM; 028 029 import org.vmmagic.pragma.*; 030 import org.vmmagic.unboxed.*; 031 032 /** 033 * This abstract class implements the core functionality of generic 034 * two-generation copying collectors. Nursery collections occur when 035 * either the heap is full or the nursery is full. The nursery size 036 * is determined by an optional command line argument. If undefined, 037 * the nursery size is "infinite", so nursery collections only occur 038 * when the heap is full (this is known as a flexible-sized nursery 039 * collector). Thus both fixed and flexible nursery sizes are 040 * supported. Full heap collections occur when the nursery size has 041 * dropped to a statically defined threshold, 042 * <code>NURSERY_THRESHOLD</code><p> 043 * 044 * See also Plan.java for general comments on local vs global plan 045 * classes. 046 */ 047 @Uninterruptible 048 public abstract class Gen extends StopTheWorld { 049 050 /***************************************************************************** 051 * 052 * Constants 053 */ 054 055 /** 056 * 057 */ 058 public static final float DEFAULT_PRETENURE_THRESHOLD_FRACTION = 0.5f; // if object is bigger than this fraction of nursery, pretenure to LOS 059 protected static final float SURVIVAL_ESTIMATE = 0.8f; // est yield 060 protected static final float MATURE_FRACTION = 0.5f; // est yield 061 private static final float WORST_CASE_COPY_EXPANSION = 1.5f; // worst case for addition of one word overhead due to address based hashing 062 public static final boolean IGNORE_REMSETS = false; 063 public static final boolean USE_NON_HEAP_OBJECT_REFERENCE_WRITE_BARRIER = false; 064 public static final boolean USE_OBJECT_BARRIER_FOR_AASTORE = false; // choose between slot and object barriers 065 public static final boolean USE_OBJECT_BARRIER_FOR_PUTFIELD = false; // choose between slot and object barriers 066 public static final boolean USE_OBJECT_BARRIER = USE_OBJECT_BARRIER_FOR_AASTORE || USE_OBJECT_BARRIER_FOR_PUTFIELD; 067 068 /** Fraction of available virtual memory to give to the nursery (if contiguous) */ 069 protected static final float NURSERY_VM_FRACTION = 0.15f; 070 071 /** Switch between a contiguous and discontiguous nursery (experimental) */ 072 static final boolean USE_DISCONTIGUOUS_NURSERY = false; 073 074 // Allocators 075 public static final int ALLOC_NURSERY = ALLOC_DEFAULT; 076 public static final int ALLOC_MATURE = StopTheWorld.ALLOCATORS + 1; 077 public static final int ALLOC_MATURE_MINORGC = StopTheWorld.ALLOCATORS + 2; 078 public static final int ALLOC_MATURE_MAJORGC = StopTheWorld.ALLOCATORS + 3; 079 080 public static final int SCAN_NURSERY = 0; 081 public static final int SCAN_MATURE = 1; 082 083 /***************************************************************************** 084 * 085 * Class fields 086 */ 087 088 /** 089 * 090 */ 091 092 /* Statistics */ 093 protected static final BooleanCounter fullHeap = new BooleanCounter("majorGC", true, true); 094 private static final Timer fullHeapTime = new Timer("majorGCTime", false, true); 095 protected static final EventCounter wbFast; 096 protected static final EventCounter wbSlow; 097 public static final SizeCounter nurseryMark; 098 public static final SizeCounter nurseryCons; 099 100 /* The nursery space is where all new objects are allocated by default */ 101 private static final VMRequest vmRequest = USE_DISCONTIGUOUS_NURSERY ? VMRequest.create() : VMRequest.create(NURSERY_VM_FRACTION, true); 102 public static final CopySpace nurserySpace = new CopySpace("nursery", false, vmRequest); 103 104 public static final int NURSERY = nurserySpace.getDescriptor(); 105 private static final Address NURSERY_START = nurserySpace.getStart(); 106 107 /***************************************************************************** 108 * 109 * Instance fields 110 */ 111 112 /* status fields */ 113 114 /** 115 * 116 */ 117 public boolean gcFullHeap = false; 118 public boolean nextGCFullHeap = false; 119 120 /* The trace object */ 121 public final Trace nurseryTrace = new Trace(metaDataSpace); 122 123 /** 124 * Remset pools 125 */ 126 127 /** 128 * 129 */ 130 public final SharedDeque modbufPool = new SharedDeque("modBufs",metaDataSpace, 1); 131 public final SharedDeque remsetPool = new SharedDeque("remSets",metaDataSpace, 1); 132 public final SharedDeque arrayRemsetPool = new SharedDeque("arrayRemSets",metaDataSpace, 2); 133 134 /* 135 * Class initializer 136 */ 137 static { 138 if (GATHER_WRITE_BARRIER_STATS) { 139 wbFast = new EventCounter("wbFast"); 140 wbSlow = new EventCounter("wbSlow"); 141 } else { 142 wbFast = null; 143 wbSlow = null; 144 } 145 if (Stats.GATHER_MARK_CONS_STATS) { 146 nurseryMark = new SizeCounter("nurseryMark", true, true); 147 nurseryCons = new SizeCounter("nurseryCons", true, true); 148 } else { 149 nurseryMark = null; 150 nurseryCons = null; 151 } 152 } 153 154 /***************************************************************************** 155 * 156 * Collection 157 */ 158 159 /** 160 * {@inheritDoc} 161 */ 162 @Override 163 public void forceFullHeapCollection() { 164 nextGCFullHeap = true; 165 } 166 167 @Override 168 @NoInline 169 public void collectionPhase(short phaseId) { 170 if (phaseId == SET_COLLECTION_KIND) { 171 super.collectionPhase(phaseId); 172 gcFullHeap = requiresFullHeapCollection(); 173 return; 174 } 175 176 if (phaseId == PREPARE) { 177 nurserySpace.prepare(true); 178 if (traceFullHeap()){ 179 if (gcFullHeap) { 180 if (Stats.gatheringStats()) fullHeap.set(); 181 fullHeapTime.start(); 182 } 183 super.collectionPhase(phaseId); 184 185 // we can throw away the remsets (but not modbuf) for a full heap GC 186 remsetPool.clearDeque(1); 187 arrayRemsetPool.clearDeque(2); 188 } 189 return; 190 } 191 192 if (phaseId == CLOSURE) { 193 if (!traceFullHeap()) { 194 nurseryTrace.prepare(); 195 } 196 return; 197 } 198 199 if (phaseId == RELEASE) { 200 nurserySpace.release(); 201 switchNurseryZeroingApproach(nurserySpace); 202 modbufPool.clearDeque(1); 203 remsetPool.clearDeque(1); 204 arrayRemsetPool.clearDeque(2); 205 if (!traceFullHeap()) { 206 nurseryTrace.release(); 207 } else { 208 super.collectionPhase(phaseId); 209 if (gcFullHeap) fullHeapTime.stop(); 210 } 211 nextGCFullHeap = (getPagesAvail() < Options.nurserySize.getMinNursery()); 212 return; 213 } 214 215 super.collectionPhase(phaseId); 216 } 217 218 @Override 219 public final boolean collectionRequired(boolean spaceFull, Space space) { 220 int availableNurseryPages = Options.nurserySize.getMaxNursery() - nurserySpace.reservedPages(); 221 222 /* periodically recalculate nursery pretenure threshold */ 223 Plan.pretenureThreshold = (int) ((availableNurseryPages<<LOG_BYTES_IN_PAGE) * Options.pretenureThresholdFraction.getValue()); 224 225 if (availableNurseryPages <= 0) { 226 return true; 227 } 228 229 if (virtualMemoryExhausted()) { 230 return true; 231 } 232 233 if (spaceFull && space != nurserySpace) { 234 nextGCFullHeap = true; 235 } 236 237 return super.collectionRequired(spaceFull, space); 238 } 239 240 /** 241 * Determine if this GC should be a full heap collection. 242 * 243 * @return <code>true</code> is this GC should be a full heap collection. 244 */ 245 protected boolean requiresFullHeapCollection() { 246 if (userTriggeredCollection && Options.fullHeapSystemGC.getValue()) { 247 return true; 248 } 249 250 if (nextGCFullHeap || collectionAttempt > 1) { 251 // Forces full heap collection 252 return true; 253 } 254 255 if (virtualMemoryExhausted()) { 256 return true; 257 } 258 259 return false; 260 } 261 262 /** 263 * Independent of how many pages remain in the page budget (a function of 264 * heap size), we must ensure we never exhaust virtual memory. Therefore 265 * we must never let the nursery grow to the extent that it can't be 266 * copied into the mature space. 267 * 268 * @return {@code true} if the nursery has grown to the extent that it may not be 269 * able to be copied into the mature space. 270 */ 271 private boolean virtualMemoryExhausted() { 272 return ((int)(getCollectionReserve() * WORST_CASE_COPY_EXPANSION)) >= getMaturePhysicalPagesAvail(); 273 } 274 275 /***************************************************************************** 276 * 277 * Correctness 278 */ 279 280 /***************************************************************************** 281 * 282 * Accounting 283 */ 284 285 /** 286 * {@inheritDoc} 287 * Simply add the nursery's contribution to that of 288 * the superclass. 289 */ 290 @Override 291 public int getPagesUsed() { 292 return (nurserySpace.reservedPages() + super.getPagesUsed()); 293 } 294 295 /** 296 * Return the number of pages available for allocation, <i>assuming 297 * all future allocation is to the nursery</i>. 298 * 299 * @return The number of pages available for allocation, <i>assuming 300 * all future allocation is to the nursery</i>. 301 */ 302 @Override 303 public int getPagesAvail() { 304 return super.getPagesAvail() >> 1; 305 } 306 307 /** 308 * Return the number of pages reserved for collection. 309 */ 310 @Override 311 public int getCollectionReserve() { 312 return nurserySpace.reservedPages() + super.getCollectionReserve(); 313 } 314 315 /** 316 * Return the number of pages available for allocation into the mature 317 * space. 318 * 319 * @return The number of pages available for allocation into the mature 320 * space. 321 */ 322 public abstract int getMaturePhysicalPagesAvail(); 323 324 /***************************************************************************** 325 * 326 * Miscellaneous 327 */ 328 329 /** 330 * Return {@code true} if the address resides within the nursery 331 * 332 * @param addr The object to be tested 333 * @return {@code true} if the address resides within the nursery 334 */ 335 @Inline 336 static boolean inNursery(Address addr) { 337 if (USE_DISCONTIGUOUS_NURSERY) 338 return Map.getDescriptorForAddress(addr) == NURSERY; 339 else 340 return addr.GE(NURSERY_START); 341 } 342 343 /** 344 * Return {@code true} if the object resides within the nursery 345 * 346 * @param obj The object to be tested 347 * @return {@code true} if the object resides within the nursery 348 */ 349 @Inline 350 static boolean inNursery(ObjectReference obj) { 351 return inNursery(obj.toAddress()); 352 } 353 354 /** 355 * @return Does the mature space do copying ? 356 */ 357 protected boolean copyMature() { 358 return false; 359 } 360 361 /** 362 * Print pre-collection statistics. In this class we prefix the output 363 * indicating whether the collection was full heap or not. 364 */ 365 @Override 366 public void printPreStats() { 367 if ((Options.verbose.getValue() >= 1) && (gcFullHeap)) 368 Log.write("[Full heap]"); 369 super.printPreStats(); 370 } 371 372 /** 373 * Accessor method to allow the generic generational code in Gen.java 374 * to access the mature space. 375 * 376 * @return The mature space, set by each subclass of <code>Gen</code>. 377 */ 378 protected abstract Space activeMatureSpace(); 379 380 /** 381 * @return {@code true} if we should trace the whole heap during collection. True if 382 * we're ignoring remsets or if we're doing a full heap GC. 383 */ 384 public final boolean traceFullHeap() { 385 return IGNORE_REMSETS || gcFullHeap; 386 } 387 388 @Override 389 public final boolean isCurrentGCNursery() { 390 return !(IGNORE_REMSETS || gcFullHeap); 391 } 392 393 @Override 394 public final boolean lastCollectionFullHeap() { 395 return gcFullHeap; 396 } 397 398 @Override 399 public boolean willNeverMove(ObjectReference object) { 400 if (Space.isInSpace(NURSERY, object)) 401 return false; 402 return super.willNeverMove(object); 403 } 404 405 @Override 406 public int sanityExpectedRC(ObjectReference object, int sanityRootRC) { 407 Space space = Space.getSpaceForObject(object); 408 409 // Nursery 410 if (space == Gen.nurserySpace) { 411 return SanityChecker.DEAD; 412 } 413 414 // Immortal spaces 415 if (space == Gen.immortalSpace || space == Gen.vmSpace) { 416 return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD; 417 } 418 419 // Mature space (nursery collection) 420 if (VM.activePlan.global().isCurrentGCNursery()) { 421 return SanityChecker.UNSURE; 422 } 423 424 // Mature space (full heap collection) 425 return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD; 426 } 427 428 @Override 429 @Interruptible 430 protected void registerSpecializedMethods() { 431 TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, GenNurseryTraceLocal.class); 432 super.registerSpecializedMethods(); 433 } 434 435 @Interruptible 436 @Override 437 public void fullyBooted() { 438 super.fullyBooted(); 439 nurserySpace.setZeroingApproach(Options.nurseryZeroing.getNonTemporal(), Options.nurseryZeroing.getConcurrent()); 440 } 441 }