jdk-24/test/hotspot/jtreg/gc/testlibrary/g1/MixedGCProvoker.java

102 lines
4.2 KiB
Java

/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package gc.testlibrary.g1;
import static java.util.stream.IntStream.range;
import static jdk.test.lib.Asserts.assertTrue;
import static jdk.test.whitebox.WhiteBox.getWhiteBox;
import java.util.ArrayList;
import java.util.List;
import gc.testlibrary.Helpers;
import jdk.test.lib.Asserts;
/**
* Utility class to reliably provoke a mixed GC. The class allocates several arrays and
* promotes them to the old generation. All GCs are triggered by Whitebox to ensure that they occur.
* Must use G1.
*/
public class MixedGCProvoker {
/**
* Allocate a few objects that are supposed to end up in the old generation as they are held live by the
* given array. Caller must make sure by running this test with e.g. -XX:+AlwaysTenure that the objects
* to actually be tenured.
* Mixes live and dead objects, allocating about two regions worth of objects.
* @param liveOldObjects Array receiving the live objects after this method.
* @param g1HeapRegionSize Size of a G1 heap region.
* @param arraySize Size of the byte arrays to use.
*/
public static void allocateOldObjects(
List<byte[]> liveOldObjects,
int g1HeapRegionSize,
int arraySize) {
var toUnreachable = new ArrayList<byte[]>();
// Allocates buffer and promotes it to the old gen. Mix live and dead old objects.
// allocate about two regions of old memory. At least one full old region will guarantee
// mixed collection in the future
range(0, g1HeapRegionSize/arraySize).forEach(n -> {
liveOldObjects.add(new byte[arraySize]);
toUnreachable.add(new byte[arraySize]);
});
// Do one young collection, AlwaysTenure will force promotion.
getWhiteBox().youngGC();
// Check it is promoted & keep alive
Asserts.assertTrue(getWhiteBox().isObjectInOldGen(liveOldObjects), "List of the objects is suppose to be in OldGen");
Asserts.assertTrue(getWhiteBox().isObjectInOldGen(toUnreachable), "List of the objects is suppose to be in OldGen");
}
/**
* Provoke at least one mixed gc by performing a concurrent collection
* and triggering two GCs.
* @param liveOldObjects The objects supposed to survive this marking cycle.
*/
public static void provokeMixedGC(List<byte[]> liveOldObjects) {
getWhiteBox().g1RunConcurrentGC();
getWhiteBox().youngGC(); // the "Prepare Mixed" gc
getWhiteBox().youngGC(); // the "Mixed" gc
// check that liveOldObjects still alive
assertTrue(getWhiteBox().isObjectInOldGen(liveOldObjects), "List of the objects is suppose to be in OldGen");
}
/**
* Provoke a mixed GC on a G1 heap with the given heap region size.
* @param g1HeapRegionSize The size of your regions in bytes
*/
public static void allocateAndProvokeMixedGC(int g1HeapRegionSize) {
final var arraySize = 20_000;
var liveOldObjects = new ArrayList<byte[]>();
getWhiteBox().fullGC(); // Make sure the heap is in a known state.
allocateOldObjects(liveOldObjects, g1HeapRegionSize, arraySize);
provokeMixedGC(liveOldObjects);
}
}