/* * 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(); } }