Skip to content

Commit 7ee70e4

Browse files
[GR-60468] Introduce a metaspace.
PullRequest: graal/21459
2 parents f4cd3b4 + b5caff6 commit 7ee70e4

File tree

45 files changed

+1144
-611
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1144
-611
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AddressRangeCommittedMemoryProvider.java

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public class AddressRangeCommittedMemoryProvider extends ChunkBasedCommittedMemo
108108
protected static final int COMMIT_FAILED = 2;
109109

110110
private static final OutOfMemoryError NODE_ALLOCATION_FAILED = new OutOfMemoryError("Could not allocate node for free list, OS may be out of memory.");
111+
private static final OutOfMemoryError OUT_OF_METASPACE = new OutOfMemoryError("Could not allocate a metaspace chunk because the metaspace is exhausted.");
111112
private static final OutOfMemoryError ALIGNED_OUT_OF_ADDRESS_SPACE = new OutOfMemoryError("Could not allocate an aligned heap chunk because the heap address space is exhausted. " +
112113
"Consider increasing the address space size (see option -XX:ReservedAddressSpaceSize).");
113114
private static final OutOfMemoryError UNALIGNED_OUT_OF_ADDRESS_SPACE = new OutOfMemoryError("Could not allocate an unaligned heap chunk because the heap address space is exhausted. " +
@@ -129,7 +130,8 @@ public class AddressRangeCommittedMemoryProvider extends ChunkBasedCommittedMemo
129130
protected FreeListNode unusedListHead;
130131
protected long unusedListCount;
131132

132-
protected UnsignedWord reservedSpaceSize;
133+
protected UnsignedWord reservedAddressSpaceSize;
134+
protected UnsignedWord reservedMetaspaceSize;
133135

134136
protected Pointer collectedHeapBegin;
135137
protected UnsignedWord collectedHeapSize;
@@ -212,7 +214,7 @@ private static int initialize(Pointer spaceBegin, UnsignedWord spaceSize, Pointe
212214
@SuppressWarnings("hiding")
213215
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
214216
protected int initializeFields(Pointer spaceBegin, UnsignedWord reservedSpaceSize, Pointer collectedHeapBegin) {
215-
this.reservedSpaceSize = reservedSpaceSize;
217+
this.reservedAddressSpaceSize = reservedSpaceSize;
216218
this.collectedHeapBegin = collectedHeapBegin;
217219
this.collectedHeapSize = spaceBegin.add(reservedSpaceSize).subtract(collectedHeapBegin);
218220

@@ -320,12 +322,38 @@ public int tearDown() {
320322

321323
@Uninterruptible(reason = "Tear-down in progress.")
322324
protected int unmapAddressSpace(PointerBase heapBase) {
323-
if (VirtualMemoryProvider.get().free(heapBase, reservedSpaceSize) != 0) {
325+
if (VirtualMemoryProvider.get().free(heapBase, reservedAddressSpaceSize) != 0) {
324326
return CEntryPointErrors.FREE_ADDRESS_SPACE_FAILED;
325327
}
326328
return CEntryPointErrors.NO_ERROR;
327329
}
328330

331+
@Override
332+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
333+
public Pointer allocateMetaspaceChunk(UnsignedWord nbytes, UnsignedWord alignment) {
334+
WordPointer allocOut = UnsafeStackValue.get(WordPointer.class);
335+
int error = allocateInHeapAddressSpace(nbytes, alignment, allocOut);
336+
if (error == NO_ERROR) {
337+
if (VMInspectionOptions.hasNativeMemoryTrackingSupport()) {
338+
NativeMemoryTracking.singleton().trackCommit(nbytes, NmtCategory.Metaspace);
339+
}
340+
return allocOut.read();
341+
}
342+
throw reportMetaspaceChunkAllocationFailed(error);
343+
}
344+
345+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
346+
protected OutOfMemoryError reportMetaspaceChunkAllocationFailed(int error) {
347+
/* Explicitly don't use OutOfMemoryUtil as the metaspace is not part of the Java heap. */
348+
if (error == OUT_OF_ADDRESS_SPACE) {
349+
throw OUT_OF_METASPACE;
350+
} else if (error == COMMIT_FAILED) {
351+
throw METASPACE_CHUNK_COMMIT_FAILED;
352+
} else {
353+
throw VMError.shouldNotReachHereAtRuntime();
354+
}
355+
}
356+
329357
@Override
330358
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
331359
public Pointer allocateAlignedChunk(UnsignedWord nbytes, UnsignedWord alignment) {
@@ -698,7 +726,7 @@ protected void mergeNodes(FreeListNode target, FreeListNode obsolete) {
698726
private void increaseBounds(FreeListNode node, Pointer otherStart, UnsignedWord otherSize) {
699727
assert getNodeEnd(node).equal(otherStart) || otherStart.add(otherSize).equal(node.getStart()) : "must be adjacent";
700728
assert UnsignedUtils.isAMultiple(otherSize, getGranularity());
701-
assert otherSize.belowOrEqual(reservedSpaceSize);
729+
assert otherSize.belowOrEqual(reservedAddressSpaceSize);
702730

703731
Pointer newStart = PointerUtils.min(node.getStart(), otherStart);
704732
UnsignedWord newSize = node.getSize().add(otherSize);
@@ -707,7 +735,7 @@ private void increaseBounds(FreeListNode node, Pointer otherStart, UnsignedWord
707735

708736
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
709737
protected void trimBounds(FreeListNode fit, Pointer newStart, UnsignedWord newSize) {
710-
assert newSize.belowOrEqual(reservedSpaceSize);
738+
assert newSize.belowOrEqual(reservedAddressSpaceSize);
711739
assert fit.getStart().equal(newStart) && newSize.belowThan(fit.getSize()) ||
712740
fit.getStart().belowThan(newStart) && getNodeEnd(fit).equal(newStart.add(newSize));
713741

@@ -790,7 +818,12 @@ private boolean isInAllocList(FreeListNode node) {
790818

791819
@Override
792820
public UnsignedWord getReservedAddressSpaceSize() {
793-
return reservedSpaceSize;
821+
return reservedAddressSpaceSize;
822+
}
823+
824+
@Override
825+
public UnsignedWord getReservedMetaspaceSize() {
826+
return reservedMetaspaceSize;
794827
}
795828

796829
/** Keeps track of unused memory. */

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.genscavenge;
2626

27+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
28+
2729
import org.graalvm.nativeimage.c.struct.RawField;
2830
import org.graalvm.nativeimage.c.struct.RawStructure;
2931
import org.graalvm.word.Pointer;
@@ -112,19 +114,21 @@ public static boolean isEmpty(AlignedHeader that) {
112114

113115
/** Allocate uninitialized memory within this AlignedHeapChunk. */
114116
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
115-
static Pointer allocateMemory(AlignedHeader that, UnsignedWord size) {
116-
Pointer result = Word.nullPointer();
117+
public static Pointer tryAllocateMemory(AlignedHeader that, UnsignedWord size) {
117118
UnsignedWord available = HeapChunk.availableObjectMemory(that);
118-
if (size.belowOrEqual(available)) {
119-
result = HeapChunk.getTopPointer(that);
120-
Pointer newTop = result.add(size);
121-
HeapChunk.setTopPointerCarefully(that, newTop);
119+
if (size.aboveThan(available)) {
120+
return Word.nullPointer();
122121
}
122+
123+
Pointer result = HeapChunk.getTopPointer(that);
124+
Pointer newTop = result.add(size);
125+
HeapChunk.setTopPointerCarefully(that, newTop);
123126
return result;
124127
}
125128

126129
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
127130
public static AlignedHeader getEnclosingChunk(Object obj) {
131+
assert ObjectHeaderImpl.isAlignedObject(obj);
128132
Pointer ptr = Word.objectToUntrackedPointer(obj);
129133
return getEnclosingChunkFromObjectPointer(ptr);
130134
}
@@ -144,7 +148,8 @@ public static UnsignedWord getObjectOffset(AlignedHeader that, Pointer objectPoi
144148
return objectPointer.subtract(objectsStart);
145149
}
146150

147-
static void walkObjects(AlignedHeader that, ObjectVisitor visitor) {
151+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
152+
public static void walkObjects(AlignedHeader that, ObjectVisitor visitor) {
148153
HeapChunk.walkObjectsFrom(that, getObjectsStart(that), visitor);
149154
}
150155

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.oracle.svm.core.genscavenge.compacting.PlanningVisitor;
4646
import com.oracle.svm.core.genscavenge.compacting.RuntimeCodeCacheFixupWalker;
4747
import com.oracle.svm.core.genscavenge.compacting.SweepingVisitor;
48+
import com.oracle.svm.core.genscavenge.metaspace.MetaspaceImpl;
4849
import com.oracle.svm.core.genscavenge.remset.BrickTable;
4950
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
5051
import com.oracle.svm.core.graal.RuntimeCompilation;
@@ -107,7 +108,7 @@
107108
*/
108109
final class CompactingOldGeneration extends OldGeneration {
109110

110-
private final Space space = new Space("Old", "O", false, HeapParameters.getMaxSurvivorSpaces() + 1);
111+
private final Space space = new Space("Old", "O", false, getAge());
111112
private final MarkStack markStack = new MarkStack();
112113

113114
private final GreyObjectsWalker toGreyObjectsWalker = new GreyObjectsWalker();
@@ -141,11 +142,6 @@ void absorb(YoungGeneration youngGen) {
141142
}
142143
}
143144

144-
@Override
145-
void appendChunk(AlignedHeapChunk.AlignedHeader hdr) {
146-
space.appendAlignedHeapChunk(hdr);
147-
}
148-
149145
@Override
150146
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
151147
void blackenDirtyCardRoots(GreyToBlackObjectVisitor visitor, GreyToBlackObjRefVisitor refVisitor) {
@@ -178,7 +174,7 @@ boolean scanGreyObjects(boolean incrementalGc) {
178174
public Object promoteAlignedObject(Object original, AlignedHeapChunk.AlignedHeader originalChunk, Space originalSpace) {
179175
if (!GCImpl.getGCImpl().isCompleteCollection()) {
180176
assert originalSpace.isFromSpace();
181-
return space.copyAlignedObject(original, originalSpace);
177+
return ObjectPromoter.copyAlignedObject(original, originalSpace, space);
182178
}
183179
assert originalSpace == space;
184180
ObjectHeader oh = Heap.getHeap().getObjectHeader();
@@ -195,7 +191,7 @@ public Object promoteAlignedObject(Object original, AlignedHeapChunk.AlignedHead
195191
* change during compaction, so we must add a field to store it, which increases the
196192
* object's size. The easiest way to handle this is to copy the object.
197193
*/
198-
result = space.copyAlignedObject(original, originalSpace);
194+
result = ObjectPromoter.copyAlignedObject(original, originalSpace, space);
199195
assert !ObjectHeaderImpl.hasIdentityHashFromAddressInline(oh.readHeaderFromObject(result));
200196
}
201197
ObjectHeaderImpl.setMarked(result);
@@ -209,7 +205,7 @@ public Object promoteAlignedObject(Object original, AlignedHeapChunk.AlignedHead
209205
protected Object promoteUnalignedObject(Object original, UnalignedHeapChunk.UnalignedHeader originalChunk, Space originalSpace) {
210206
if (!GCImpl.getGCImpl().isCompleteCollection()) {
211207
assert originalSpace.isFromSpace();
212-
space.promoteUnalignedHeapChunk(originalChunk, originalSpace);
208+
ObjectPromoter.promoteUnalignedHeapChunk(originalChunk, originalSpace, space);
213209
return original;
214210
}
215211
assert originalSpace == space;
@@ -226,9 +222,9 @@ protected boolean promotePinnedObject(Object obj, HeapChunk.Header<?> originalCh
226222
if (!GCImpl.getGCImpl().isCompleteCollection()) {
227223
assert originalSpace != space && originalSpace.isFromSpace();
228224
if (isAligned) {
229-
space.promoteAlignedHeapChunk((AlignedHeapChunk.AlignedHeader) originalChunk, originalSpace);
225+
ObjectPromoter.promoteAlignedHeapChunk((AlignedHeapChunk.AlignedHeader) originalChunk, originalSpace, space);
230226
} else {
231-
space.promoteUnalignedHeapChunk((UnalignedHeapChunk.UnalignedHeader) originalChunk, originalSpace);
227+
ObjectPromoter.promoteUnalignedHeapChunk((UnalignedHeapChunk.UnalignedHeader) originalChunk, originalSpace, space);
232228
}
233229
return true;
234230
}
@@ -309,6 +305,13 @@ private void fixupReferencesBeforeCompaction(ChunkReleaser chunkReleaser, Timers
309305
oldFixupImageHeapTimer.stop();
310306
}
311307

308+
Timer oldFixupMetaspaceTimer = timers.oldFixupMetaspace.start();
309+
try {
310+
fixupMetaspace();
311+
} finally {
312+
oldFixupMetaspaceTimer.stop();
313+
}
314+
312315
Timer oldFixupThreadLocalsTimer = timers.oldFixupThreadLocals.start();
313316
try {
314317
for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) {
@@ -356,6 +359,20 @@ private void fixupImageHeapRoots(ImageHeapInfo info) {
356359
}
357360
}
358361

362+
@Uninterruptible(reason = "Avoid unnecessary safepoint checks in GC for performance.")
363+
private void fixupMetaspace() {
364+
if (!MetaspaceImpl.isSupported()) {
365+
return;
366+
}
367+
368+
if (SerialGCOptions.useRememberedSet()) {
369+
/* Cards have been cleaned and roots re-marked during the initial scan. */
370+
MetaspaceImpl.singleton().walkDirtyObjects(fixupVisitor, refFixupVisitor, false);
371+
} else {
372+
MetaspaceImpl.singleton().walkObjects(fixupVisitor);
373+
}
374+
}
375+
359376
@Uninterruptible(reason = "Avoid unnecessary safepoint checks in GC for performance.")
360377
private void fixupUnalignedChunkReferences(ChunkReleaser chunkReleaser) {
361378
UnalignedHeapChunk.UnalignedHeader uChunk = space.getFirstUnalignedHeapChunk();

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CopyingOldGeneration.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ final class CopyingOldGeneration extends OldGeneration {
5252
@Platforms(Platform.HOSTED_ONLY.class)
5353
CopyingOldGeneration(String name) {
5454
super(name);
55-
int age = HeapParameters.getMaxSurvivorSpaces() + 1;
56-
this.fromSpace = new Space("Old", "O", false, age);
57-
this.toSpace = new Space("Old To", "O", true, age);
55+
this.fromSpace = new Space("Old", "O", false, getAge());
56+
this.toSpace = new Space("Old To", "O", true, getAge());
5857
}
5958

6059
@Override
@@ -76,15 +75,15 @@ public void walkObjects(ObjectVisitor visitor) {
7675
@Override
7776
public Object promoteAlignedObject(Object original, AlignedHeapChunk.AlignedHeader originalChunk, Space originalSpace) {
7877
assert originalSpace.isFromSpace();
79-
return getToSpace().copyAlignedObject(original, originalSpace);
78+
return ObjectPromoter.copyAlignedObject(original, originalSpace, getToSpace());
8079
}
8180

8281
@AlwaysInline("GC performance")
8382
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
8483
@Override
8584
protected Object promoteUnalignedObject(Object original, UnalignedHeapChunk.UnalignedHeader originalChunk, Space originalSpace) {
8685
assert originalSpace.isFromSpace();
87-
getToSpace().promoteUnalignedHeapChunk(originalChunk, originalSpace);
86+
ObjectPromoter.promoteUnalignedHeapChunk(originalChunk, originalSpace, getToSpace());
8887
return original;
8988
}
9089

@@ -93,9 +92,9 @@ protected Object promoteUnalignedObject(Object original, UnalignedHeapChunk.Unal
9392
protected boolean promotePinnedObject(Object obj, HeapChunk.Header<?> originalChunk, boolean isAligned, Space originalSpace) {
9493
assert originalSpace.isFromSpace();
9594
if (isAligned) {
96-
getToSpace().promoteAlignedHeapChunk((AlignedHeapChunk.AlignedHeader) originalChunk, originalSpace);
95+
ObjectPromoter.promoteAlignedHeapChunk((AlignedHeapChunk.AlignedHeader) originalChunk, originalSpace, getToSpace());
9796
} else {
98-
getToSpace().promoteUnalignedHeapChunk((UnalignedHeapChunk.UnalignedHeader) originalChunk, originalSpace);
97+
ObjectPromoter.promoteUnalignedHeapChunk((UnalignedHeapChunk.UnalignedHeader) originalChunk, originalSpace, getToSpace());
9998
}
10099
return true;
101100
}
@@ -146,11 +145,6 @@ Space getToSpace() {
146145
return toSpace;
147146
}
148147

149-
@Override
150-
void appendChunk(AlignedHeapChunk.AlignedHeader hdr) {
151-
getToSpace().appendAlignedHeapChunk(hdr);
152-
}
153-
154148
@Override
155149
void swapSpaces() {
156150
assert getFromSpace().isEmpty() : "fromSpace should be empty.";

0 commit comments

Comments
 (0)