--- old/test/serviceability/tmtools/jstat/GcCapacityTest.java 2016-11-16 21:43:21.652578674 +0300 +++ new/test/serviceability/tmtools/jstat/GcCapacityTest.java 2016-11-16 21:43:21.544578678 +0300 @@ -45,7 +45,7 @@ measurement1.assertConsistency(); // Provoke a gc and verify the changed values - GcProvoker gcProvoker = GcProvoker.createGcProvoker(); + GcProvoker gcProvoker = new GcProvoker(); gcProvoker.provokeGc(); JstatGcCapacityResults measurement2 = jstatGcTool.measure(); measurement2.assertConsistency(); --- old/test/serviceability/tmtools/jstat/GcCauseTest01.java 2016-11-16 21:43:22.264578651 +0300 +++ new/test/serviceability/tmtools/jstat/GcCauseTest01.java 2016-11-16 21:43:22.156578655 +0300 @@ -47,7 +47,7 @@ JstatGcCauseResults measurement1 = jstatGcTool.measure(); measurement1.assertConsistency(); - GcProvoker gcProvoker = GcProvoker.createGcProvoker(); + GcProvoker gcProvoker = new GcProvoker(); // Provoke GC then run the tool again and get the results asserting that they are reasonable gcProvoker.provokeGc(); --- old/test/serviceability/tmtools/jstat/GcCauseTest02.java 2016-11-16 21:43:22.764578632 +0300 +++ new/test/serviceability/tmtools/jstat/GcCauseTest02.java 2016-11-16 21:43:22.656578636 +0300 @@ -27,10 +27,11 @@ * Test scenario: * tests forces debuggee application eat ~70% of heap and runs jstat. * jstat should show that ~70% of heap (OC/OU ~= 70%). + * @requires vm.opt.ExplicitGCInvokesConcurrent != true * @modules java.base/jdk.internal.misc * @library /test/lib * @library ../share - * @run main/othervm -XX:+UsePerfData -Xmx128M -XX:MaxMetaspaceSize=128M GcCauseTest02 + * @run main/othervm -XX:+UsePerfData -XX:InitialHeapSize=128M -XX:MaxHeapSize=128M -XX:MaxMetaspaceSize=128M GcCauseTest02 */ import utils.*; @@ -47,10 +48,12 @@ JstatGcCauseResults measurement1 = jstatGcTool.measure(); measurement1.assertConsistency(); - GcProvoker gcProvoker = GcProvoker.createGcProvoker(); + GcProvoker gcProvoker = new GcProvoker(); // Eat metaspace and heap then run the tool again and get the results asserting that they are reasonable - gcProvoker.eatMetaspaceAndHeap(targetMemoryUsagePercent); + gcProvoker.allocateAvailableMetaspaceAndHeap(targetMemoryUsagePercent); + // Collect garbage. Also update VM statistics + System.gc(); JstatGcCauseResults measurement2 = jstatGcTool.measure(); measurement2.assertConsistency(); --- old/test/serviceability/tmtools/jstat/GcNewTest.java 2016-11-16 21:43:23.256578614 +0300 +++ new/test/serviceability/tmtools/jstat/GcNewTest.java 2016-11-16 21:43:23.152578618 +0300 @@ -46,7 +46,7 @@ JstatGcNewResults measurement1 = jstatGcTool.measure(); measurement1.assertConsistency(); - GcProvoker gcProvoker = GcProvoker.createGcProvoker(); + GcProvoker gcProvoker = new GcProvoker(); // Provoke GC and run the tool again gcProvoker.provokeGc(); --- old/test/serviceability/tmtools/jstat/GcTest01.java 2016-11-16 21:43:23.864578591 +0300 +++ new/test/serviceability/tmtools/jstat/GcTest01.java 2016-11-16 21:43:23.760578595 +0300 @@ -50,7 +50,7 @@ JstatGcResults measurement1 = jstatGcTool.measure(); measurement1.assertConsistency(); - GcProvoker gcProvoker = GcProvoker.createGcProvoker(); + GcProvoker gcProvoker = new GcProvoker(); // Provoke GC then run the tool again and get the results // asserting that they are reasonable --- old/test/serviceability/tmtools/jstat/GcTest02.java 2016-11-16 21:43:24.364578573 +0300 +++ new/test/serviceability/tmtools/jstat/GcTest02.java 2016-11-16 21:43:24.256578577 +0300 @@ -28,10 +28,11 @@ * Test scenario: * tests forces debuggee application eat ~70% of heap and runs jstat. * jstat should show that ~70% of heap is utilized (OC/OU ~= 70%). + * @requires vm.opt.ExplicitGCInvokesConcurrent != true * @modules java.base/jdk.internal.misc * @library /test/lib * @library ../share - * @run main/othervm -XX:+UsePerfData -Xmx128M -XX:MaxMetaspaceSize=128M GcTest02 + * @run main/othervm -XX:+UsePerfData -XX:InitialHeapSize=128M -XX:MaxHeapSize=128M -XX:MaxMetaspaceSize=128M GcTest02 */ public class GcTest02 { @@ -47,10 +48,12 @@ JstatGcResults measurement1 = jstatGcTool.measure(); measurement1.assertConsistency(); - GcProvoker gcProvoker = GcProvoker.createGcProvoker(); + GcProvoker gcProvoker = new GcProvoker(); // Eat metaspace and heap then run the tool again and get the results asserting that they are reasonable - gcProvoker.eatMetaspaceAndHeap(targetMemoryUsagePercent); + gcProvoker.allocateAvailableMetaspaceAndHeap(targetMemoryUsagePercent); + // Collect garbage. Also updates VM statistics + System.gc(); JstatGcResults measurement2 = jstatGcTool.measure(); measurement2.assertConsistency(); --- old/test/serviceability/tmtools/jstat/utils/GcProvoker.java 2016-11-16 21:43:24.872578554 +0300 +++ new/test/serviceability/tmtools/jstat/utils/GcProvoker.java 2016-11-16 21:43:24.756578558 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -22,34 +22,136 @@ */ package utils; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.MemoryUsage; +import java.util.ArrayList; +import java.util.List; + /** - * This is an interface used to provoke GC and perform other GC-related + * This is an class used to provoke GC and perform other GC-related * procedures * */ -public interface GcProvoker { +public class GcProvoker{ + + // Uses fixed small objects to avoid Humongous objects allocation in G1 + public static final int MEMORY_CHUNK = 2048; + public static final float ALLOCATION_TOLERANCE = 0.05f; + + public static List allocatedMetaspace; + public static List allocatedMemory; + + private final Runtime runtime; + + private List allocateHeap(float targetUsage) { + long maxMemory = runtime.maxMemory(); + List list = new ArrayList<>(); + long used = 0; + long target = (long) (maxMemory * targetUsage); + while (used < target) { + try { + list.add(new byte[MEMORY_CHUNK]); + used += MEMORY_CHUNK; + } catch (OutOfMemoryError e) { + list = null; + throw new RuntimeException("Unexpected OOME '" + e.getMessage() + "' while eating " + targetUsage + " of heap memory."); + } + } + return list; + } + + private List allocateAvailableHeap(float targetUsage) { + // Calculates size of free memory after allocation with small tolerance. + long minFreeMemory = (long) ((1.0 - (targetUsage + ALLOCATION_TOLERANCE)) * runtime.maxMemory()); + List list = new ArrayList<>(); + do { + try { + list.add(new byte[MEMORY_CHUNK]); + } catch (OutOfMemoryError e) { + list = null; + throw new RuntimeException("Unexpected OOME '" + e.getMessage() + "' while eating " + targetUsage + " of heap memory."); + } + } while (runtime.freeMemory() > minFreeMemory); + return list; + } /** - * The default implementation - * - * @return the default GC provoker + * This method provokes a GC */ - public static GcProvoker createGcProvoker() { - return new GcProvokerImpl(); + public void provokeGc() { + for (int i = 0; i < 3; i++) { + long edenSize = Pools.getEdenCommittedSize(); + long heapSize = Pools.getHeapCommittedSize(); + float targetPercent = ((float) edenSize) / (heapSize); + if ((targetPercent < 0) || (targetPercent > 1.0)) { + throw new RuntimeException("Error in the percent calculation" + " (eden size: " + edenSize + ", heap size: " + heapSize + ", calculated eden percent: " + targetPercent + ")"); + } + allocateHeap(targetPercent); + allocateHeap(targetPercent); + System.gc(); + } } /** - * This method provokes a GC + * Allocates heap and metaspace upon exit not less than targetMemoryUsagePercent percents + * of heap and metaspace have been consumed. + * + * @param targetMemoryUsagePercent how many percent of heap and metaspace to + * allocate */ - public void provokeGc(); + public void allocateMetaspaceAndHeap(float targetMemoryUsagePercent) { + // Metaspace should be filled before Java Heap to prevent unexpected OOME + // in the Java Heap while filling Metaspace + allocatedMetaspace = eatMetaspace(targetMemoryUsagePercent); + allocatedMemory = allocateHeap(targetMemoryUsagePercent); + } + /** - * Eats heap and metaspace Upon exit targetMemoryUsagePercent percents of - * heap and metaspace is have been eaten + * Allocates heap and metaspace upon exit targetMemoryUsagePercent percents + * of heap and metaspace have been consumed. * * @param targetMemoryUsagePercent how many percent of heap and metaspace to - * eat + * allocate */ - public void eatMetaspaceAndHeap(float targetMemoryUsagePercent); + public void allocateAvailableMetaspaceAndHeap(float targetMemoryUsagePercent) { + // Metaspace should be filled before Java Heap to prevent unexpected OOME + // in the Java Heap while filling Metaspace + allocatedMetaspace = eatMetaspace(targetMemoryUsagePercent); + allocatedMemory = allocateAvailableHeap(targetMemoryUsagePercent); + } + + private List eatMetaspace(float targetUsage) { + List list = new ArrayList<>(); + final String metaspacePoolName = "Metaspace"; + MemoryPoolMXBean metaspacePool = null; + for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { + if (pool.getName().contains(metaspacePoolName)) { + metaspacePool = pool; + break; + } + } + if (metaspacePool == null) { + throw new RuntimeException("MXBean for Metaspace pool wasn't found"); + } + float currentUsage; + GeneratedClassProducer gp = new GeneratedClassProducer(); + do { + try { + list.add(gp.create(0)); + } catch (OutOfMemoryError oome) { + list = null; + throw new RuntimeException("Unexpected OOME '" + oome.getMessage() + "' while eating " + targetUsage + " of Metaspace."); + } + MemoryUsage memoryUsage = metaspacePool.getUsage(); + currentUsage = (((float) memoryUsage.getUsed()) / memoryUsage.getMax()); + } while (currentUsage < targetUsage); + return list; + } + + public GcProvoker() { + runtime = Runtime.getRuntime(); + } } --- old/test/serviceability/tmtools/jstat/utils/GcProvokerImpl.java 2016-11-16 21:43:25.476578532 +0300 +++ /dev/null 2016-10-27 15:20:32.540744930 +0300 @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2015, 2016, 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 utils; - -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryPoolMXBean; -import java.lang.management.MemoryUsage; -import java.util.ArrayList; -import java.util.List; - -/** - * - * Utilities to provoke GC in various ways - */ -public class GcProvokerImpl implements GcProvoker { - - private static List eatenMetaspace; - private static List eatenMemory; - - static List eatHeapMemory(float targetUsage) { - long maxMemory = Runtime.getRuntime().maxMemory(); - // uses fixed small objects to avoid Humongous objects allocation in G1 - int memoryChunk = 2048; - List list = new ArrayList<>(); - long used = 0; - long target = (long) (maxMemory * targetUsage); - while (used < target) { - try { - list.add(new byte[memoryChunk]); - used += memoryChunk; - } catch (OutOfMemoryError e) { - list = null; - throw new RuntimeException("Unexpected OOME '" + e.getMessage() + "' while eating " + targetUsage + " of heap memory."); - } - } - return list; - } - - @Override - public void provokeGc() { - for (int i = 0; i < 3; i++) { - long edenSize = Pools.getEdenCommittedSize(); - long heapSize = Pools.getHeapCommittedSize(); - float targetPercent = ((float) edenSize) / (heapSize); - if ((targetPercent < 0) || (targetPercent > 1.0)) { - throw new RuntimeException("Error in the percent calculation" + " (eden size: " + edenSize + ", heap size: " + heapSize + ", calculated eden percent: " + targetPercent + ")"); - } - eatHeapMemory(targetPercent); - eatHeapMemory(targetPercent); - System.gc(); - } - } - - @Override - public void eatMetaspaceAndHeap(float targetMemoryUsagePercent) { - // Metaspace should be filled before Java Heap to prevent unexpected OOME - // in the Java Heap while filling Metaspace - eatenMetaspace = eatMetaspace(targetMemoryUsagePercent); - eatenMemory = eatHeapMemory(targetMemoryUsagePercent); - } - - private static List eatMetaspace(float targetUsage) { - List list = new ArrayList<>(); - final String metaspacePoolName = "Metaspace"; - MemoryPoolMXBean metaspacePool = null; - for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { - if (pool.getName().contains(metaspacePoolName)) { - metaspacePool = pool; - break; - } - } - if (metaspacePool == null) { - throw new RuntimeException("MXBean for Metaspace pool wasn't found"); - } - float currentUsage; - GeneratedClassProducer gp = new GeneratedClassProducer(); - do { - try { - list.add(gp.create(0)); - } catch (OutOfMemoryError oome) { - list = null; - throw new RuntimeException("Unexpected OOME '" + oome.getMessage() + "' while eating " + targetUsage + " of Metaspace."); - } - MemoryUsage memoryUsage = metaspacePool.getUsage(); - currentUsage = (((float) memoryUsage.getUsed()) / memoryUsage.getMax()); - } while (currentUsage < targetUsage); - return list; - } - - public GcProvokerImpl() { - } - -}