Path: blob/master/test/hotspot/jtreg/vmTestbase/metaspace/gc/MetaspaceBaseGC.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.lang.management.ManagementFactory;27import java.lang.management.MemoryPoolMXBean;28import java.lang.management.MemoryUsage;29import java.lang.reflect.Field;30import java.lang.reflect.InvocationHandler;31import java.lang.reflect.Method;32import java.lang.reflect.Proxy;33import java.net.URL;34import java.net.URLClassLoader;35import java.nio.file.Files;36import java.nio.file.Paths;37import java.util.HashMap;38import java.util.HashSet;39import java.util.List;40import java.util.Map;41import java.util.Set;42import jdk.internal.misc.Unsafe;4344/**45* Test that checks how GC works with Metaspace and "Compared Class Space".46*47* It comprises 3 test cases:48* <ul>49* <li>testcase1 - checks that used/committed memory doesn't grow50* when gc is invoked</li>51* <li>testcase2 - checks that gc is invoked when the class metadata u52* sage reaches MetaspaceSize</li>53* <li>testcase3 - checks used/committed grow, inspite of gc is invoked</li>54* </ul>55*56* It's supposed that this class will be executed with various setting of VM57* flags. Via execute args it's possible to say which test cases to run and58* what space to test: Metaspace or Compared Class Space.59*/60public abstract class MetaspaceBaseGC {6162// storage of loaded classes63private final Map<String, MetaspaceBaseGC.Foo> loadedClasses = new HashMap<>();64private static int counter = 0;6566// pool to test67protected MemoryPoolMXBean pool = null;6869// memory page size70protected static final long PAGE_SIZE = detectPageSize();7172// true when PAGE_SIZE is large and73protected boolean useLargepages = false;7475// where the log will be saved76protected String gclogFileName = null;7778protected final Set<String> vmArgs = new HashSet<>();7980protected abstract void parseArgs(String args[]);81protected abstract String getPoolName();82protected abstract void doCheck();8384public final void run(String args[]) {85configure(args);86if (pool == null) {87System.out.println("%%% Cannot pull the pool, most likely 32-bits only");88return;89}90System.out.println("%%% Working with " + getPoolName());91for (String vmA: vmArgs) {92if (vmA.contains("Metaspace") || vmA.contains("Compressed")) {93System.out.println("% " + vmA);94}95}96doCheck();97System.out.println("% Test passed.");98}99100101protected void configure(String args[]) {102vmArgs.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments());103104System.out.println(vmArgs);105106pool = getMemoryPool(getPoolName());107if (pool == null) {108return; // nothing to check109}110for (String arg: vmArgs) {111if (arg.startsWith("-Xlog:gc") && arg.length() > 8) {112gclogFileName = arg.substring(arg.lastIndexOf(':') + 1);113}114}115parseArgs(args);116}117118119/**120* Imitates class loading.121* Each invocation of this method causes a new class loader object is created122* and a new class is loaded by this class loader.123* Method throws OOM when run out of memory.124*125* @param times how many classes to load126* @param keepRefs true, if references to created classes should be stored127*/128protected void loadNewClasses(int times, boolean keepRefs) {129for (int i = 0; i < times; i++) {130try {131String jarUrl = "file:" + counter + ".jar";132counter++;133URL[] urls = new URL[]{new URL(jarUrl)};134URLClassLoader cl = new URLClassLoader(urls);135MetaspaceBaseGC.Foo foo = (MetaspaceBaseGC.Foo) Proxy.newProxyInstance(cl,136new Class[]{MetaspaceBaseGC.Foo.class},137new MetaspaceBaseGC.FooInvocationHandler(new MetaspaceBaseGC.FooBar()));138if (keepRefs) {139loadedClasses.put(jarUrl, foo);140}141} catch (java.net.MalformedURLException badThing) {142// should never occur143System.err.println("Unexpeted error: " + badThing);144throw new RuntimeException(badThing);145}146}147148}149150/**151* Cleans references to loaded classes.152*/153protected void cleanLoadedClasses() {154loadedClasses.clear();155}156157/**158* Invokes System.gc() and sleeps a little.159*/160protected void gc() {161System.gc();162try {163Thread.currentThread().sleep(500);164} catch (Exception whatever) {165}166}167168/**169* Reads gc.log file and returns it as a list of lines.170* It's supposed that the test is executed with -Xlog:gc:gc.log option.171*172* @return List of strings the gc.log file is comprised.173* @throws IOException if problem occurred while reading.174*/175protected List<String> readGCLog() throws IOException {176return Files.readAllLines(Paths.get(".", gclogFileName));177}178179/**180* Reads gc.log file and counts GC induced by metaspace.181* @return how many times GC induced by metaspace has occurred.182*/183protected int getMetaspaceGCCount() {184int count = 0;185try {186for (String line: readGCLog()) {187if (line.indexOf("Metadata GC ") > 0) {188count++;189}190}191return count;192} catch (Throwable t) {193t.printStackTrace(System.err);194return -1;195}196}197198protected String lastGCLogLine() {199if (gclogFileName == null) {200return "";201}202try {203List<String> list = Files.readAllLines(Paths.get(".", gclogFileName));204return list.get(list.size() - 1);205} catch (IOException e) {206return "File not found";207}208}209210/**211* Does it best to checks if the last GC was caused by metaspace.212*213* This method looks into gc.log file (if -Xloggc:file is given) and returns214* true if the last line in the log contains the "Metadata" word.215* It's not very reliable way to check, log might not be flushed yet.216*217* @return218*/219protected boolean isMetaspaceGC() {220return lastGCLogLine().contains("Metadata");221}222223/**224* Prints amounts of used and committed metaspace preceeded by the message225* @param mesg a message to printed prior usages226*/227protected void printMemoryUsage(String mesg) {228MemoryUsage mu = pool.getUsage();229printMemoryUsage(mesg, mu.getUsed(), mu.getCommitted());230}231protected void printMemoryUsage(String mesg, long v1, long v2) {232System.out.println(mesg + ": " + bytes2k(v1) + " : " + bytes2k(v2));233}234protected String bytes2k(long v) {235return (v / 1024) + "k";236}237238239240/**241* @return amount of used memory242*/243public long getUsed() {244return pool.getUsage().getUsed();245}246247/**248* @return amount of committed memory249*/250public long getCommitted() {251return pool.getUsage().getCommitted();252}253254private static MemoryPoolMXBean getMemoryPool(String name) {255List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();256for (MemoryPoolMXBean pool : pools) {257if (pool.getName().equals(name)) {258return pool;259}260}261return null;262}263264private static long detectPageSize() {265try {266Unsafe unsafe = Unsafe.getUnsafe();267268int pageSize = unsafe.pageSize();269System.out.println("Page size: " + pageSize);270return pageSize;271} catch (Exception e) {272throw new Fault("Cannot detect page size");273}274}275276277long parseValue(String s) {278s = s.toLowerCase();279int multiplier = 1;280switch (s.charAt(s.length() - 1)) {281case 'g': multiplier = 1024*1024*1024; break;282case 'm': multiplier = 1024*1024; break;283case 'k': multiplier = 1024; break;284}285if (multiplier == 1) {286return Long.parseLong(s);287} else {288return Long.parseLong(s.substring(0, s.length() - 1)) * multiplier;289}290}291292public static interface Foo {293}294295public static class FooBar implements Foo {296}297298class FooInvocationHandler implements InvocationHandler {299private final Foo foo;300301FooInvocationHandler(MetaspaceBaseGC.Foo foo) {302this.foo = foo;303}304305@Override306public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {307return method.invoke(foo, args);308}309}310311}312313314