| /* |
| * 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:<metaspace|compressed>"); |
| } |
| |
| /** |
| * @return name of the MemoryPoolMXBean under test |
| */ |
| @Override |
| protected String getPoolName() { |
| return pool_name; |
| } |
| |
| @Override |
| protected void doCheck() { |
| checkForNotGrowing(); |
| checkForGrowing(); |
| } |
| |
| } |