/* * 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 liveOldObjects, int g1HeapRegionSize, int arraySize) { var toUnreachable = new ArrayList(); // 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 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(); getWhiteBox().fullGC(); // Make sure the heap is in a known state. allocateOldObjects(liveOldObjects, g1HeapRegionSize, arraySize); provokeMixedGC(liveOldObjects); } }