--- /dev/null 2018-05-02 09:10:36.097102948 -0700 +++ new/test/hotspot/jtreg/vmTestbase/metaspace/gc/MemoryUsageTest.java 2018-05-08 10:20:13.557632166 -0700 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2013, 2018, 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 metaspace.gc; + +/** + * Test observers the progress on used/committed memory. + * MemoryPoolMXBean is used for that purpose. + * + * Depending on command line option the test checks either Metaspace or + * Compressed Class Space area. + * + * This test checks two things: + * 1) Loading/Unloading classes doesn't cause memory increase + * 2) Loading classes causes permanent increase of memory. + */ +public class MemoryUsageTest extends MetaspaceBaseGC { + + private String pool_name; + + public static void main(String[] args) { + new MemoryUsageTest().run(args); + } + + + + /** + * Loads new classes by bunches and invokes GC after each bunch. + * Expected behavior: used/committed should stop growing after 5 iterations. + */ + public void checkForNotGrowing() { + + long p_used = 0; + long p_committed = 0; + + System.out.println("%%%% Loading classes without storing refs, invoking gc manually"); + final int numberOfIteration = 10; + for (int i = 0; i < numberOfIteration; i++) { + loadNewClasses(500, false); + gc(); + printMemoryUsage("% " + i + " "); + if (i == numberOfIteration / 2) { + // used/committed in the middle of the step. + p_used = getUsed(); + p_committed = getCommitted(); + } + + } + long used = getUsed(); + long committed = getCommitted(); + + // loading classes without keeping references to them + // should not affect used/commited metaspace + // but OK, let's allow some noise such as +/-8K + if (Math.abs((int) (used - p_used)) > 1024*8) { + throw new Fault("Used amount should be stable: " + + p_used + " --> " + used); + } + if (Math.abs((int) (committed - p_committed)) > 1024*8) { + throw new Fault("Committed amount should be stable: " + + p_committed + " --> " + committed); + } + + } + + /** + * Loads new classes by bunches and invokes GC after each bunch. + * Expected behavior: used/committed should keep growing + */ + public void checkForGrowing() { + long used = 0; + long committed = 0; + long p_used = 0 ; + long p_committed = 0; + + // loading new classes, starting to keep references. + // both used and commited metaspace should grow up. + System.out.println("%%%% Loading classes, refs are stored, gc is invoking manually"); + for (int i = 0; i < 10; i++) { + try { + loadNewClasses(1000, true); + } catch (OutOfMemoryError oom) { + String message = oom.getMessage().toLowerCase(); + if (message.contains("metaspace") || message.contains("compressed class space")) { + System.out.println("% oom is ok: " + oom); + return; + } else { + System.err.println("% unexpected OOM" + oom); + throw new Fault(oom); + } + } + + gc(); + printMemoryUsage("% " + i + " "); + p_used = used; + p_committed = committed; + used = getUsed(); + committed = getCommitted(); + if (i > 0 && used <= p_used) { + throw new Fault("Used amount reduced unexpectedly " + + p_used + " --> " + used); + } + if (i > 0 && committed < p_committed) { + throw new Fault("Used amount reduced unexpectedly " + + p_committed + " --> " + committed); + } + } + } + + /** + * Looks up for memory pool name. + * @param args command line options + */ + @Override + protected void parseArgs(String[] args) { + if (args.length != 1) { + printUsage(); + throw new Fault("MemoryPool is not specified"); + } + + String a = args[0]; + if (a.equalsIgnoreCase("-pool:compressed")) { + pool_name = "Compressed Class Space"; + } else if (a.equalsIgnoreCase("-pool:metaspace")) { + pool_name = "Metaspace"; + } else { + printUsage(); + throw new Fault("Unrecongnized argument: " + a); + } + } + + private void printUsage() { + System.err.println("Usage: "); + System.err.println("java [-Xms..] [-XX:MetaspaceSize=..] [-XX:MaxMetaspaceSize=..] \\"); + System.err.println(" " + MemoryUsageTest.class.getCanonicalName() + " -pool:"); + } + + /** + * @return name of the MemoryPoolMXBean under test + */ + @Override + protected String getPoolName() { + return pool_name; + } + + @Override + protected void doCheck() { + checkForNotGrowing(); + checkForGrowing(); + } + +}