61
61
import com .oracle .svm .core .locks .VMMutex ;
62
62
import com .oracle .svm .core .log .Log ;
63
63
import com .oracle .svm .core .memory .NullableNativeMemory ;
64
+ import com .oracle .svm .core .metaspace .Metaspace ;
64
65
import com .oracle .svm .core .nmt .NativeMemoryTracking ;
65
66
import com .oracle .svm .core .nmt .NmtCategory ;
66
67
import com .oracle .svm .core .os .ChunkBasedCommittedMemoryProvider ;
77
78
78
79
/**
79
80
* Reserves a fixed-size address range and provides memory from it by committing and uncommitting
80
- * virtual memory within that range.
81
+ * virtual memory within that range. The address space is shared by the null regions, the
82
+ * {@link Metaspace}, the image heap, and the collected Java heap.
81
83
* <p>
82
84
* The main objective of this code is to keep external fragmentation low so that an
83
85
* {@linkplain Isolate} is unlikely to run out of memory because its address space is exhausted. To
@@ -122,59 +124,65 @@ public class AddressRangeCommittedMemoryProvider extends ChunkBasedCommittedMemo
122
124
*/
123
125
private final VMMutex lock = new VMMutex ("freeList" );
124
126
125
- /** Contains free blocks that are large enough to fit allocations. */
127
+ protected UnsignedWord reservedAddressSpaceSize ;
128
+ private Pointer metaspaceBegin ;
129
+ private Pointer metaspaceTop ;
130
+ private Pointer metaspaceEnd ;
131
+ protected Pointer collectedHeapBegin ;
132
+ protected UnsignedWord collectedHeapSize ;
133
+
134
+ /**
135
+ * Contains free blocks for the collected Java heap that are large enough to fit allocations.
136
+ */
126
137
protected FreeListNode allocListHead ;
127
138
protected long allocListCount ;
128
139
129
- /** Contains all free blocks, including small blocks that are needed for coalescing. */
140
+ /**
141
+ * Contains all free blocks for the collected Java heap, including small blocks that are needed
142
+ * for coalescing.
143
+ */
130
144
protected FreeListNode unusedListHead ;
131
145
protected long unusedListCount ;
132
146
133
- protected UnsignedWord reservedAddressSpaceSize ;
134
- protected UnsignedWord reservedMetaspaceSize ;
135
-
136
- protected Pointer collectedHeapBegin ;
137
- protected UnsignedWord collectedHeapSize ;
138
-
139
147
@ Platforms (Platform .HOSTED_ONLY .class )
140
148
public AddressRangeCommittedMemoryProvider () {
141
149
assert SubstrateOptions .SpawnIsolates .getValue ();
142
150
}
143
151
144
152
@ Override
145
153
@ Uninterruptible (reason = "Still being initialized." )
146
- public int initialize (WordPointer heapBasePointer , IsolateArguments arguments ) {
147
- UnsignedWord reserved = Word .unsigned (IsolateArgumentAccess .readLong (arguments , IsolateArgumentParser .getOptionIndex (SubstrateGCOptions .ReservedAddressSpaceSize )));
148
- if (reserved .equal (0 )) {
154
+ public int initialize (WordPointer heapBaseOut , IsolateArguments arguments ) {
155
+ UnsignedWord reservedSize = Word .unsigned (IsolateArgumentAccess .readLong (arguments , IsolateArgumentParser .getOptionIndex (SubstrateGCOptions .ReservedAddressSpaceSize )));
156
+ if (reservedSize .equal (0 )) {
149
157
/*
150
158
* Reserve a 32 GB address space, except if a larger heap size was specified, or if the
151
159
* maximum address space size is less than that.
152
160
*/
153
161
UnsignedWord maxHeapSize = Word .unsigned (IsolateArgumentAccess .readLong (arguments , IsolateArgumentParser .getOptionIndex (SubstrateGCOptions .MaxHeapSize )));
154
- reserved = UnsignedUtils .max (maxHeapSize , Word .unsigned (MIN_RESERVED_ADDRESS_SPACE_SIZE ));
162
+ reservedSize = UnsignedUtils .max (maxHeapSize , Word .unsigned (MIN_RESERVED_ADDRESS_SPACE_SIZE ));
155
163
}
156
- reserved = UnsignedUtils .min (reserved , ReferenceAccess .singleton ().getMaxAddressSpaceSize ());
164
+ reservedSize = UnsignedUtils .min (reservedSize , ReferenceAccess .singleton ().getMaxAddressSpaceSize ());
157
165
158
- UnsignedWord alignment = unsigned (Heap .getHeap ().getPreferredAddressSpaceAlignment ());
159
- WordPointer beginOut = StackValue .get (WordPointer .class );
160
- int errorCode = reserveHeapMemory (reserved , alignment , arguments , beginOut );
166
+ UnsignedWord alignment = unsigned (Heap .getHeap ().getHeapBaseAlignment ());
167
+ WordPointer reservedBeginPtr = StackValue .get (WordPointer .class );
168
+ int errorCode = reserveHeapMemory (reservedSize , alignment , arguments , reservedBeginPtr );
161
169
if (errorCode != CEntryPointErrors .NO_ERROR ) {
162
170
return errorCode ;
163
171
}
164
172
165
- Pointer begin = beginOut .read ();
173
+ Pointer reservedBegin = reservedBeginPtr .read ();
166
174
WordPointer imageHeapEndOut = StackValue .get (WordPointer .class );
167
- errorCode = ImageHeapProvider .get ().initialize (begin , reserved , heapBasePointer , imageHeapEndOut );
175
+ errorCode = ImageHeapProvider .get ().initialize (reservedBegin , reservedSize , heapBaseOut , imageHeapEndOut );
168
176
if (errorCode != CEntryPointErrors .NO_ERROR ) {
169
- freeOnInitializeError (begin , reserved );
177
+ freeOnInitializeError (reservedBegin , reservedSize );
170
178
return errorCode ;
171
179
}
172
180
173
- CEntryPointSnippets .initBaseRegisters (heapBasePointer .read ());
181
+ CEntryPointSnippets .initBaseRegisters (heapBaseOut .read ());
174
182
WordPointer runtimeHeapBeginOut = StackValue .get (WordPointer .class );
175
- errorCode = getCollectedHeapBegin (arguments , begin , reserved , imageHeapEndOut .read (), runtimeHeapBeginOut );
183
+ errorCode = initializeCollectedHeapBegin (arguments , reservedBegin , reservedSize , imageHeapEndOut .read (), runtimeHeapBeginOut );
176
184
if (errorCode != CEntryPointErrors .NO_ERROR ) {
177
- freeOnInitializeError (begin , reserved );
185
+ freeOnInitializeError (reservedBegin , reservedSize );
178
186
return errorCode ;
179
187
}
180
188
@@ -183,40 +191,58 @@ public int initialize(WordPointer heapBasePointer, IsolateArguments arguments) {
183
191
* because the image heap was not initialized when we were called, so we invoke a static
184
192
* method that loads a new reference to our instance.
185
193
*/
186
- errorCode = initialize (begin , reserved , runtimeHeapBeginOut .read ());
194
+ errorCode = initialize (reservedBegin , reservedSize , runtimeHeapBeginOut .read ());
187
195
if (errorCode != CEntryPointErrors .NO_ERROR ) {
188
- freeOnInitializeError (begin , reserved );
196
+ freeOnInitializeError (reservedBegin , reservedSize );
189
197
}
190
198
return errorCode ;
191
199
}
192
200
193
201
@ Uninterruptible (reason = "Still being initialized." )
194
- protected int getCollectedHeapBegin (@ SuppressWarnings ("unused" ) IsolateArguments arguments , @ SuppressWarnings ("unused" ) Pointer begin , @ SuppressWarnings ( "unused" ) UnsignedWord reserved ,
195
- Pointer imageHeapEnd , WordPointer collectedHeapBeginOut ) {
196
- Pointer result = roundUp (imageHeapEnd , getGranularity ( ));
197
- collectedHeapBeginOut .write (result );
202
+ protected int initializeCollectedHeapBegin (@ SuppressWarnings ("unused" ) IsolateArguments arguments , @ SuppressWarnings ("unused" ) Pointer reservedBegin ,
203
+ @ SuppressWarnings ( "unused" ) UnsignedWord reservedSize , Pointer imageHeapEnd , WordPointer collectedHeapBeginOut ) {
204
+ assert PointerUtils . isAMultiple (imageHeapEnd , Word . unsigned ( SubstrateOptions . getPageSize () ));
205
+ collectedHeapBeginOut .write (imageHeapEnd );
198
206
return CEntryPointErrors .NO_ERROR ;
199
207
}
200
208
201
209
@ NeverInline ("Ensure a newly looked up value is used as 'this', now that the image heap is initialized" )
202
210
@ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE )
203
- private static int initialize (Pointer spaceBegin , UnsignedWord spaceSize , Pointer collectedHeapBegin ) {
204
- if (VMInspectionOptions .hasNativeMemoryTrackingSupport ()) {
205
- UnsignedWord imageHeapAddressSpace = ImageHeapProvider .get ().getImageHeapAddressSpaceSize ();
206
- UnsignedWord javaHeapAddressSpace = spaceSize .subtract (imageHeapAddressSpace );
207
- NativeMemoryTracking .singleton ().trackReserve (javaHeapAddressSpace , NmtCategory .JavaHeap );
208
- }
209
-
211
+ private static int initialize (Pointer reservedBegin , UnsignedWord reservedSize , Pointer collectedHeapBegin ) {
210
212
AddressRangeCommittedMemoryProvider provider = (AddressRangeCommittedMemoryProvider ) ChunkBasedCommittedMemoryProvider .get ();
211
- return provider .initializeFields (spaceBegin , spaceSize , collectedHeapBegin );
213
+ return provider .initializeFields (reservedBegin , reservedSize , collectedHeapBegin );
212
214
}
213
215
216
+ @ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
214
217
@ SuppressWarnings ("hiding" )
218
+ protected int initializeFields (Pointer reservedBegin , UnsignedWord reservedSize , Pointer collectedHeapBegin ) {
219
+ this .reservedAddressSpaceSize = reservedSize ;
220
+
221
+ initializeMetaspaceFields ();
222
+ return initializeCollectedHeapFields (reservedBegin , reservedSize , collectedHeapBegin );
223
+ }
224
+
215
225
@ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
216
- protected int initializeFields (Pointer spaceBegin , UnsignedWord reservedSpaceSize , Pointer collectedHeapBegin ) {
217
- this .reservedAddressSpaceSize = reservedSpaceSize ;
226
+ protected void initializeMetaspaceFields () {
227
+ int metaspaceSize = SerialAndEpsilonGCOptions .getReservedMetaspaceSize ();
228
+ this .metaspaceBegin = KnownIntrinsics .heapBase ().add (HeapImpl .getMetaspaceOffsetInAddressSpace ());
229
+ this .metaspaceTop = metaspaceBegin ;
230
+ this .metaspaceEnd = metaspaceTop .add (metaspaceSize );
231
+
232
+ if (VMInspectionOptions .hasNativeMemoryTrackingSupport () && metaspaceSize > 0 ) {
233
+ NativeMemoryTracking .singleton ().trackReserve (metaspaceSize , NmtCategory .Metaspace );
234
+ }
235
+ }
236
+
237
+ @ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
238
+ @ SuppressWarnings ("hiding" )
239
+ private int initializeCollectedHeapFields (Pointer reservedBegin , UnsignedWord reservedSize , Pointer collectedHeapBegin ) {
218
240
this .collectedHeapBegin = collectedHeapBegin ;
219
- this .collectedHeapSize = spaceBegin .add (reservedSpaceSize ).subtract (collectedHeapBegin );
241
+ this .collectedHeapSize = reservedSize .subtract (collectedHeapBegin .subtract (reservedBegin ));
242
+
243
+ if (VMInspectionOptions .hasNativeMemoryTrackingSupport ()) {
244
+ NativeMemoryTracking .singleton ().trackReserve (collectedHeapSize , NmtCategory .JavaHeap );
245
+ }
220
246
221
247
FreeListNode node = allocNodeOrNull (collectedHeapBegin , collectedHeapSize );
222
248
if (node .isNull ()) {
@@ -227,10 +253,20 @@ protected int initializeFields(Pointer spaceBegin, UnsignedWord reservedSpaceSiz
227
253
this .unusedListCount = 1 ;
228
254
this .allocListHead = node ;
229
255
this .allocListCount = 1 ;
230
-
231
256
return CEntryPointErrors .NO_ERROR ;
232
257
}
233
258
259
+ @ Override
260
+ public UnsignedWord getCollectedHeapAddressSpaceSize () {
261
+ return collectedHeapSize ;
262
+ }
263
+
264
+ @ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
265
+ public boolean isInMetaspace (Pointer ptr ) {
266
+ /* Checking against begin and end does not need any locking. */
267
+ return ptr .aboveOrEqual (metaspaceBegin ) && ptr .belowThan (metaspaceEnd );
268
+ }
269
+
234
270
@ Uninterruptible (reason = "Still being initialized." )
235
271
protected int reserveHeapMemory (UnsignedWord reserved , UnsignedWord alignment , IsolateArguments arguments , WordPointer beginOut ) {
236
272
Pointer begin = reserveHeapMemory0 (reserved , alignment , arguments );
@@ -329,29 +365,48 @@ protected int unmapAddressSpace(PointerBase heapBase) {
329
365
}
330
366
331
367
@ Override
332
- @ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
368
+ @ Uninterruptible (reason = "Locking without transition requires that the whole critical section is uninterruptible." )
333
369
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 ();
370
+ lock .lockNoTransition ();
371
+ try {
372
+ return allocateMetaspaceChunk0 (nbytes , alignment );
373
+ } finally {
374
+ lock .unlock ();
341
375
}
342
- throw reportMetaspaceChunkAllocationFailed (error );
343
376
}
344
377
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 ) {
378
+ /**
379
+ * This method intentionally does not use {@link OutOfMemoryUtil} when reporting
380
+ * {@link OutOfMemoryError}s as the metaspace is not part of the Java heap.
381
+ */
382
+ @ Uninterruptible (reason = "Locking without transition requires that the whole critical section is uninterruptible." )
383
+ private Pointer allocateMetaspaceChunk0 (UnsignedWord nbytes , UnsignedWord alignment ) {
384
+ assert lock .isOwner ();
385
+
386
+ Pointer result = metaspaceTop ;
387
+ Pointer newTop = metaspaceTop .add (nbytes );
388
+ assert result .isNonNull ();
389
+ assert PointerUtils .isAMultiple (result , alignment );
390
+ assert UnsignedUtils .isAMultiple (newTop , alignment );
391
+
392
+ /* Check if the allocation fits into the reserved address space. */
393
+ if (newTop .aboveThan (metaspaceEnd )) {
349
394
throw OUT_OF_METASPACE ;
350
- } else if (error == COMMIT_FAILED ) {
395
+ }
396
+
397
+ /* Try to commit the memory. */
398
+ int access = VirtualMemoryProvider .Access .READ | VirtualMemoryProvider .Access .WRITE ;
399
+ Pointer actualBegin = VirtualMemoryProvider .get ().commit (result , nbytes , access );
400
+ if (actualBegin .isNull ()) {
351
401
throw METASPACE_CHUNK_COMMIT_FAILED ;
352
- } else {
353
- throw VMError .shouldNotReachHereAtRuntime ();
354
402
}
403
+
404
+ /* Update top and NMT statistics. */
405
+ metaspaceTop = newTop ;
406
+ if (VMInspectionOptions .hasNativeMemoryTrackingSupport ()) {
407
+ NativeMemoryTracking .singleton ().trackCommit (nbytes , NmtCategory .Metaspace );
408
+ }
409
+ return actualBegin ;
355
410
}
356
411
357
412
@ Override
@@ -821,11 +876,6 @@ public UnsignedWord getReservedAddressSpaceSize() {
821
876
return reservedAddressSpaceSize ;
822
877
}
823
878
824
- @ Override
825
- public UnsignedWord getReservedMetaspaceSize () {
826
- return reservedMetaspaceSize ;
827
- }
828
-
829
879
/** Keeps track of unused memory. */
830
880
@ RawStructure
831
881
protected interface FreeListNode extends PointerBase {
0 commit comments