Path: blob/master/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java
40942 views
/*1* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package gc.g1;2425/*26* @test TestGreyReclaimedHumongousObjects.java27* @bug 8069367 818527828* @requires vm.gc.G129* @summary Test handling of marked but unscanned reclaimed humongous objects.30* @modules jdk.management31* @run main/othervm -XX:+UseG1GC -Xss32m -Xmx128m -XX:G1HeapRegionSize=1m32* -XX:+UnlockExperimentalVMOptions33* -XX:+G1EagerReclaimHumongousObjects34* -XX:+G1EagerReclaimHumongousObjectsWithStaleRefs35* gc.g1.TestGreyReclaimedHumongousObjects 1048576 9036*/3738// This test spawns a bunch of threads, each of them rapidly39// allocating large objects and storing them into a circular buffer40// associated with the thread. The circular buffer results in these41// objects becoming dead in fairly short order.42//43// The situation we're trying to provoke is44//45// (1) A humongous object H is marked and added to the mark stack.46//47// (2) An evacuation pause determines H is no longer live, and48// reclaims it. This occurs before concurrent marking has gotten49// around to processing the mark stack entry for H.50//51// (3) Concurrent marking processes the mark stack entry for H. The52// bug is that it would attempt to scan the now dead object.53//54// Unfortunately, this test is *very* sensitive to configuration.55// Among the parameters that affect whether / how often we'll get into56// the desired situation within a reasonable amount of time are:57//58// - THREAD_COUNT: The number of allocating threads.59//60// - OLD_COUNT: The number of objects each thread keeps.61//62// - MAX_MEMORY: The maximum heap size.63//64// - G1HeapRegionSize65//66// - The size of the objects being allocated.67//68// The parameter values specified here:69//70// - THREAD_COUNT = 1271// - OLD_COUNT == 472// - MAX_MEMORY == 128m73// - G1HeapRegionSize = 1m74// - Object size = 1048576 (2 regions after header overhead and roundup)75//76// seems to work well at provoking the desired state fairly quickly.77// Even relatively small perturbations may change that. The key78// factors seem to be keeping the heap mostly full of live objects but79// having them become dead fairly quickly.8081import java.util.Date;82import java.util.concurrent.ExecutorService;83import java.util.concurrent.Executors;84import java.util.concurrent.ThreadFactory;85import java.util.concurrent.TimeUnit;86import com.sun.management.HotSpotDiagnosticMXBean;87import java.lang.management.ManagementFactory;8889public class TestGreyReclaimedHumongousObjects {9091static class NamedThreadFactory implements ThreadFactory {92private int threadNum = 0;9394@Override95public Thread newThread(Runnable r) {96return new Thread(r, THREAD_NAME + (threadNum++));97}98}99100static class Runner extends Thread {101private final Date startDate = new Date();102private final int obj_size;103private final Object[] old_garbage;104private int old_index = 0;105106public Runner(int obj_size) {107this.obj_size = obj_size;108old_garbage = new Object[OLD_COUNT];109}110111private void allocate_garbage() {112byte[] garbage = new byte[obj_size];113old_garbage[Math.abs(++old_index % OLD_COUNT)] = garbage;114}115116@Override117public void run() {118try {119while (!isInterrupted()) {120allocate_garbage();121Thread.sleep(0); // Yield, to ensure interruptable.122}123} catch (InterruptedException e) {124System.out.println("Aborted after "125+ (new Date().getTime() - startDate.getTime())126+ " ms");127interrupt();128}129}130}131132public static void main(String[] args) throws Exception {133HotSpotDiagnosticMXBean diagnostic =134ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);135136System.out.println("Max memory= " + MAX_MEMORY + " bytes");137138int obj_size = 0;139long seconds_to_run = 0;140if (args.length != 2) {141throw new RuntimeException("Object size argument must be supplied");142} else {143obj_size = Integer.parseInt(args[0]);144seconds_to_run = Integer.parseInt(args[1]);145}146System.out.println("Objects size= " + obj_size + " bytes");147System.out.println("Seconds to run=" + seconds_to_run);148149int region_size =150Integer.parseInt(diagnostic.getVMOption("G1HeapRegionSize").getValue());151if (obj_size < (region_size / 2)) {152throw new RuntimeException("Object size " + obj_size +153" is not humongous with region size " + region_size);154}155156ExecutorService executor =157Executors.newFixedThreadPool(THREAD_COUNT, new NamedThreadFactory());158System.out.println("Starting " + THREAD_COUNT + " threads");159160for (int i = 0; i < THREAD_COUNT; i++) {161executor.execute(new Runner(obj_size));162}163164Thread.sleep(seconds_to_run * 1000);165executor.shutdownNow();166167if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {168System.err.println("Thread pool did not terminate after 10 seconds after shutdown");169}170}171172private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory();173private static final int OLD_COUNT = 4;174private static final int THREAD_COUNT = 12;175private static final String THREAD_NAME = "TestGreyRH-";176}177178179