48c7549806
Reviewed-by: bpb, ihse
231 lines
8.6 KiB
Java
231 lines
8.6 KiB
Java
/*
|
|
* Copyright (c) 2013, 2022, 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;
|
|
|
|
import java.io.IOException;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import static metaspace.gc.MetaspaceBaseGC.PAGE_SIZE;
|
|
|
|
/**
|
|
* Test for metaspace GC
|
|
*
|
|
* <ul>
|
|
* <li>MetaspaceSize
|
|
* </ul>
|
|
* Test checks that the first GC happens when metaspace committed is next to
|
|
* MetaspaceSize value.
|
|
*
|
|
* Based on actual events (JDK 8 GC tuning document)
|
|
*
|
|
* Quating: Java SE 8 HotSpot[tm] Virtual Machine Garbage Collection Tuning
|
|
* <pre>
|
|
* Class metadata is deallocated when the corresponding Java class is unloaded.
|
|
* Java classes are unloaded as a results of garbage collection and garbage
|
|
* collections may be induced in order to unload classes and deallocate class
|
|
* metadata. When the space used for class metadata reaches a certain level
|
|
* (call it a high-water mark), a garbage collection is induced.
|
|
*
|
|
* The flag MetaspaceSize can be set higher to avoid early garbage collections
|
|
* induced for class metadata. The amount of class metadata allocated for
|
|
* an application is application dependent and general guidelines do not
|
|
* exist for the selection of MetaspaceSize. The default size of MetaspaceSize
|
|
* is platform dependent and ranges from 12 MB to about 20 MB.
|
|
* </pre>
|
|
*/
|
|
public class FirstGCTest extends MetaspaceBaseGC {
|
|
/**
|
|
* Current amount of the used metaspace
|
|
*/
|
|
protected long used = 0;
|
|
|
|
/**
|
|
* Current amount of the committed metaspace
|
|
*/
|
|
protected long committed = 0;
|
|
|
|
/**
|
|
* Previous amount of the used metaspace
|
|
*/
|
|
protected long p_used = 0 ;
|
|
|
|
/**
|
|
* Previous amount of the committed metaspace
|
|
*/
|
|
protected long p_committed = 0;
|
|
|
|
public static void main(String... args) {
|
|
new FirstGCTest().run(args);
|
|
}
|
|
|
|
// value given in -XX:metaspaceSize=<value>
|
|
private long metaspaceSize = -1;
|
|
|
|
|
|
@Override
|
|
protected void parseArgs(String[] args) {
|
|
final String XXSize = "-XX:MetaspaceSize=";
|
|
for (String va: vmArgs) {
|
|
if (va.startsWith(XXSize)) {
|
|
metaspaceSize = parseValue(va.substring(XXSize.length()));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected String getPoolName() {
|
|
return "Metaspace";
|
|
}
|
|
|
|
/**
|
|
* Check for the first GC moment.
|
|
*
|
|
* Eats memory until GC is invoked (amount of used metaspace became less);
|
|
* Checks that committed memory is close to MemaspaceSize.
|
|
* Eats memory until the second GC to check min/max ratio options have effect.
|
|
*/
|
|
@Override
|
|
public void doCheck() {
|
|
int gcCount = super.getMetaspaceGCCount();
|
|
if (gcCount == 0) {
|
|
// gc hasn't happened yet. Start loading classes.
|
|
boolean gcHappened = this.eatMemoryUntilGC(50000);
|
|
if (!gcHappened) {
|
|
throw new Fault("GC hasn't happened");
|
|
}
|
|
System.out.println("% GC: " + super.lastGCLogLine());
|
|
System.out.println("% used : " + p_used + " --> " + used);
|
|
System.out.println("% committed: " + p_committed + " --> " + committed);
|
|
checkCommitted(p_committed);
|
|
} else {
|
|
// everything has happened before
|
|
checkCommitted(detectCommittedFromGCLog());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check that committed amount is close to expected value (MetaspaceSize)
|
|
*
|
|
* @param committedAmount - value to check
|
|
*/
|
|
void checkCommitted(long committedAmount) {
|
|
if (metaspaceSize > 0) {
|
|
// -XX:MetaspaceSize is given
|
|
if (Math.abs((int) (metaspaceSize - committedAmount)) < PAGE_SIZE) {
|
|
System.out.println("% GC happened at the right moment");
|
|
return;
|
|
}
|
|
if (!isMetaspaceGC()) {
|
|
System.out.println("% GC wasn't induced by metaspace, cannot check the moment :(");
|
|
return;
|
|
}
|
|
System.err.println("%## GC happened at the wrong moment, "
|
|
+ "the amount of committed space significantly differs "
|
|
+ "from the expected amount");
|
|
System.err.println("%## Real : " + committedAmount);
|
|
System.err.println("%## Expected: " + metaspaceSize);
|
|
throw new Fault("GC happened at the wrong moment");
|
|
} else {
|
|
// -XX:MetaspaceSize is not given, check for default values
|
|
if (11_500_000 < committedAmount && committedAmount < 22_500_000) {
|
|
System.out.println("% GC happened when the committed amout was from 12 MB to about 20 MB.");
|
|
return;
|
|
}
|
|
if (!isMetaspaceGC()) {
|
|
System.out.println("% GC wasn't induced by metaspace, this is excuse");
|
|
return;
|
|
}
|
|
System.err.println("%## GC happened at the wrong moment, "
|
|
+ "the amount of committed space was expected from 12 MB to about 20 MB");
|
|
System.err.println("%## Real : " + committedAmount);
|
|
throw new Fault("It was the wrong moment when GC happened");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load new classes without keeping references to them trying to provoke GC.
|
|
* Stops if GC is detected, or number of attempts exceeds the given limit.
|
|
*
|
|
* @param times limit of attempts to provoke GC
|
|
* @return true if GC has happened, false if limit has exceeded.
|
|
*/
|
|
protected boolean eatMemoryUntilGC(int times) {
|
|
System.out.println("%%%% Loading classes");
|
|
System.out.println("% iter# : used : commited");
|
|
System.out.println("..............................");
|
|
for (int i = 1; i < times; i++) {
|
|
loadNewClasses(1, false);
|
|
if (i % 1000 == 0) {
|
|
printMemoryUsage("% " + i + " ");
|
|
}
|
|
p_used = used;
|
|
p_committed = committed;
|
|
used = getUsed();
|
|
committed = getCommitted();
|
|
|
|
if (used < p_used) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* If the first full GC has already happened we will try to detect
|
|
* the committed amount from the gc.log file.
|
|
*
|
|
* @return committed amount detected
|
|
* @throws Fault if failed to detect.
|
|
*/
|
|
protected long detectCommittedFromGCLog() {
|
|
// parse gc.log to extract the committed value from string like:
|
|
// Metaspace used 10133K, capacity 10190K, committed 10240K, reserved 10240Kl
|
|
System.out.println("%%%% Parsing gc log to detect the moment of the first GC");
|
|
String format = ".*Metaspace.* used .*, capacity .*, committed (\\d+)([KMGkmg]), reserved .*";
|
|
Pattern p = Pattern.compile(format);
|
|
try {
|
|
for (String line: readGCLog()) {
|
|
Matcher m = p.matcher(line);
|
|
if (m.matches()) {
|
|
int amount = Integer.parseInt(m.group(1));
|
|
int multi = 1;
|
|
switch (m.group(2).toLowerCase()) {
|
|
case "k": multi = 1024; break;
|
|
case "m": multi = 1024*1024; break;
|
|
case "g": multi = 1024*1024*1024; break;
|
|
}
|
|
long value = amount * multi;
|
|
System.out.println("% Committed detected: " + value);
|
|
return value;
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
throw new Fault("Cannot read from the GC log");
|
|
}
|
|
System.out.println("% String that matches pattern '" + format + "' not found in the GC log file.");
|
|
throw new Fault("Unable to detect the moment of GC from log file");
|
|
}
|
|
|
|
}
|