Path: blob/master/test/hotspot/jtreg/vmTestbase/metaspace/gc/FirstGCTest.java
41155 views
/*1* Copyright (c) 2013, 2018, 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 metaspace.gc;2425import java.io.IOException;26import java.util.regex.Matcher;27import java.util.regex.Pattern;28import static metaspace.gc.MetaspaceBaseGC.PAGE_SIZE;2930/**31* Test for metaspace GC32*33* <ul>34* <li>MetaspaceSize35* </ul>36* Test checks that the first GC happens when metaspace committed is next to37* MetaspaceSize value.38*39* Based on actual events (JDK 8 GC tuning document)40*41* Quating: Java SE 8 HotSpot[tm] Virtual Machine Garbage Collection Tuning42* <pre>43* Class metadata is deallocated when the corresponding Java class is unloaded.44* Java classes are unloaded as a results of garbage collection and garbage45* collections may be induced in order to unload classes and deallocate class46* metadata. When the space used for class metadata reaches a certain level47* (call it a high-water mark), a garbage collection is induced.48*49* The flag MetaspaceSize can be set higher to avoid early garbage collections50* induced for class metadata. The amount of class metadata allocated for51* an application is application dependent and general guidelines do not52* exist for the selection of MetaspaceSize. The default size of MetaspaceSize53* is platform dependent and ranges from 12 MB to about 20 MB.54* </pre>55*/56public class FirstGCTest extends MetaspaceBaseGC {57/**58* Current amount of the used metaspace59*/60protected long used = 0;6162/**63* Current amount of the committed metaspace64*/65protected long committed = 0;6667/**68* Previous amount of the used metaspace69*/70protected long p_used = 0 ;7172/**73* Previous amount of the committed metaspace74*/75protected long p_committed = 0;7677public static void main(String... args) {78new FirstGCTest().run(args);79}8081// value given in -XX:metaspaceSize=<value>82private long metaspaceSize = -1;838485@Override86protected void parseArgs(String[] args) {87final String XXSize = "-XX:MetaspaceSize=";88for (String va: vmArgs) {89if (va.startsWith(XXSize)) {90metaspaceSize = parseValue(va.substring(XXSize.length()));91}92}93}9495@Override96protected String getPoolName() {97return "Metaspace";98}99100/**101* Check for the first GC moment.102*103* Eats memory until GC is invoked (amount of used metaspace became less);104* Checks that committed memory is close to MemaspaceSize.105* Eats memory until the second GC to check min/max ratio options have effect.106*/107@Override108public void doCheck() {109int gcCount = super.getMetaspaceGCCount();110if (gcCount == 0) {111// gc hasn't happened yet. Start loading classes.112boolean gcHappened = this.eatMemoryUntilGC(50000);113if (!gcHappened) {114throw new Fault("GC hasn't happened");115}116System.out.println("% GC: " + super.lastGCLogLine());117System.out.println("% used : " + p_used + " --> " + used);118System.out.println("% committed: " + p_committed + " --> " + committed);119checkCommitted(p_committed);120} else {121// everything has happened before122checkCommitted(detectCommittedFromGCLog());123}124}125126/**127* Check that committed amount is close to expected value (MetaspaceSize)128*129* @param committedAmount - value to check130*/131void checkCommitted(long committedAmount) {132if (metaspaceSize > 0) {133// -XX:MetaspaceSize is given134if (Math.abs((int) (metaspaceSize - committedAmount)) < PAGE_SIZE) {135System.out.println("% GC happened at the right moment");136return;137}138if (!isMetaspaceGC()) {139System.out.println("% GC wasn't induced by metaspace, cannot check the moment :(");140return;141}142System.err.println("%## GC happened at the wrong moment, "143+ "the amount of committed space significantly differs "144+ "from the expected amount");145System.err.println("%## Real : " + committedAmount);146System.err.println("%## Exepcted: " + metaspaceSize);147throw new Fault("GC happened at the wrong moment");148} else {149// -XX:MetaspaceSize is not given, check for default values150if (11_500_000 < committedAmount && committedAmount < 22_500_000) {151System.out.println("% GC happened when the committed amout was from 12 MB to about 20 MB.");152return;153}154if (!isMetaspaceGC()) {155System.out.println("% GC wasn't induced by metaspace, this is excuse");156return;157}158System.err.println("%## GC happened at the wrong moment, "159+ "the amount of committed space was expected from 12 MB to about 20 MB");160System.err.println("%## Real : " + committedAmount);161throw new Fault("It was the wrong moment when GC happened");162}163}164165/**166* Load new classes without keeping references to them trying to provoke GC.167* Stops if GC is detected, or number of attempts exceeds the given limit.168*169* @param times limit of attempts to provoke GC170* @return true if GC has happened, false if limit has exceeded.171*/172protected boolean eatMemoryUntilGC(int times) {173System.out.println("%%%% Loading classes");174System.out.println("% iter# : used : commited");175System.out.println("..............................");176for (int i = 1; i < times; i++) {177loadNewClasses(1, false);178if (i % 1000 == 0) {179printMemoryUsage("% " + i + " ");180}181p_used = used;182p_committed = committed;183used = getUsed();184committed = getCommitted();185186if (used < p_used) {187return true;188}189}190return false;191}192193/**194* If the first full GC has already happened we will try to detect195* the committed amount from the gc.log file.196*197* @return committed amount detected198* @throws Fault if failed to detect.199*/200protected long detectCommittedFromGCLog() {201// parse gc.log to extract the committed value from string like:202// Metaspace used 10133K, capacity 10190K, committed 10240K, reserved 10240Kl203System.out.println("%%%% Parsing gc log to detect the moment of the first GC");204String format = ".*Metaspace.* used .*, capacity .*, committed (\\d+)([KMGkmg]), reserved .*";205Pattern p = Pattern.compile(format);206try {207for (String line: readGCLog()) {208Matcher m = p.matcher(line);209if (m.matches()) {210int amount = Integer.parseInt(m.group(1));211int multi = 1;212switch (m.group(2).toLowerCase()) {213case "k": multi = 1024; break;214case "m": multi = 1024*1024; break;215case "g": multi = 1024*1024*1024; break;216}217long value = amount * multi;218System.out.println("% Committed detected: " + value);219return value;220}221}222} catch (IOException e) {223throw new Fault("Cannot read from the GC log");224}225System.out.println("% String that matches pattern '" + format + "' not found in the GC log file.");226throw new Fault("Unable to detect the moment of GC from log file");227}228229}230231232