26
26
27
27
import static com .oracle .svm .core .genscavenge .CollectionPolicy .shouldCollectYoungGenSeparately ;
28
28
29
- import jdk .graal .compiler .word .Word ;
30
29
import org .graalvm .word .UnsignedWord ;
31
30
32
31
import com .oracle .svm .core .Uninterruptible ;
35
34
import com .oracle .svm .core .util .TimeUtils ;
36
35
import com .oracle .svm .core .util .UnsignedUtils ;
37
36
37
+ import jdk .graal .compiler .word .Word ;
38
+
38
39
/**
39
40
* A garbage collection policy that balances throughput and memory footprint.
40
41
*
@@ -163,7 +164,8 @@ public String getName() {
163
164
public boolean shouldCollectCompletely (boolean followingIncrementalCollection ) { // should_attempt_scavenge
164
165
guaranteeSizeParametersInitialized ();
165
166
166
- if (!followingIncrementalCollection && shouldCollectYoungGenSeparately (!SerialGCOptions .useCompactingOldGen ())) {
167
+ boolean collectYoungSeparately = shouldCollectYoungGenSeparately (!SerialGCOptions .useCompactingOldGen ());
168
+ if (!followingIncrementalCollection && collectYoungSeparately ) {
167
169
/*
168
170
* With a copying collector, default to always doing an incremental collection first
169
171
* because we expect most of the objects in the young generation to be garbage, and we
@@ -181,6 +183,12 @@ public boolean shouldCollectCompletely(boolean followingIncrementalCollection) {
181
183
*/
182
184
return true ;
183
185
}
186
+
187
+ if (!collectYoungSeparately && followingIncrementalCollection ) {
188
+ // Don't override the earlier decision to not do a full GC below (and prolong the pause)
189
+ return false ;
190
+ }
191
+
184
192
if (minorCountSinceMajorCollection * avgMinorPause .getAverage () >= CONSECUTIVE_MINOR_TO_MAJOR_COLLECTION_PAUSE_TIME_RATIO * avgMajorPause .getPaddedAverage ()) {
185
193
/*
186
194
* When we do many incremental collections in a row because they reclaim sufficient
@@ -190,7 +198,17 @@ public boolean shouldCollectCompletely(boolean followingIncrementalCollection) {
190
198
return true ;
191
199
}
192
200
193
- return false ;
201
+ UnsignedWord youngUsed = HeapImpl .getHeapImpl ().getYoungGeneration ().getChunkBytes ();
202
+ UnsignedWord oldUsed = HeapImpl .getHeapImpl ().getOldGeneration ().getChunkBytes ();
203
+
204
+ /*
205
+ * If the remaining free space in the old generation is less than what is expected to be
206
+ * needed by the next collection, do a full collection now.
207
+ */
208
+ UnsignedWord averagePromoted = UnsignedUtils .fromDouble (avgPromoted .getPaddedAverage ());
209
+ UnsignedWord promotionEstimate = UnsignedUtils .min (averagePromoted , youngUsed );
210
+ UnsignedWord oldFree = oldSize .subtract (oldUsed );
211
+ return promotionEstimate .aboveThan (oldFree );
194
212
}
195
213
196
214
private void updateAverages (boolean isSurvivorOverflow , UnsignedWord survivedChunkBytes , UnsignedWord promotedChunkBytes ) {
0 commit comments