我们如何模拟 OutOfMemory: Metaspace?
How can we simulate OutOfMemory: Metaspace?
我有一个任务是故意模拟 OutOfMemory: Metaspace 错误。我尝试了不同的方法,但 none 给了我需要的结果。有人可以为此分享好的例子吗?
我的第一次尝试(使用 javassist):
static ClassPool classPool = ClassPool.getDefault();
@SneakyThrows
public void task() {
try {
for (int i = 0; ; i++) {
Class cl = classPool.makeClass("task1.Test" + i).toClass();
}
} catch (Error er) {
Runtime.getRuntime().gc();
log.error(er.getMessage());
}
}
和 gradle.properties 文件中的设置:
org.gradle.jvmargs=-XX:MaxMetaspaceSize=70M
但是我有一个错误:
Exception: java.lang.OutOfMemoryError thrown from the
UncaughtExceptionHandler in thread "main"
我没听清楚。
我的第二次尝试:
public void task() {
try {
URL url = new File("D:/classes").toURI().toURL();
URL[] urls = {url};
ClassLoadingMXBean loadingMXBean = ManagementFactory.getClassLoadingMXBean();
List<ClassLoader> classLoaders = new ArrayList<>();
while (true) {
ClassLoader classLoader = new URLClassLoader(urls);
classLoaders.add(classLoader);
classLoader.loadClass("test1.Test1");
log.info("Total: " + loadingMXBean.getTotalLoadedClassCount());
log.info("Active: " + loadingMXBean.getLoadedClassCount());
log.info("Unloaded: " + loadingMXBean.getUnloadedClassCount());
}
} catch (Exception ex) {
log.error(ex + ex.getMessage());
}
}
没用,IDEA告诉我内存有规律
您忘记了 class加载在 JVM 中的工作方式。 classloader 将首先尝试让其父加载您要查找的 class。为了让你的测试工作,你需要一个自定义 class 加载器,它不会为你正在测试的 class 委托给它的父级。
这是一个适用于 Java 8
的示例
DummyClass.java(默认包)
public class DummyClass {
static String padding = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
}
Test.java(默认包)
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
try {
URL url = Test.class.getResource("").toURI().toURL();
System.out.println("URL = " + url);
URL[] urls = {url};
ClassLoadingMXBean loadingMXBean = ManagementFactory.getClassLoadingMXBean();
List<ClassLoader> classLoaders = new ArrayList<>();
System.out.println("Total: " + loadingMXBean.getTotalLoadedClassCount());
System.out.println("Active: " + loadingMXBean.getLoadedClassCount());
System.out.println("Unloaded: " + loadingMXBean.getUnloadedClassCount());
int i = 0;
while ( true ) {
i++;
System.out.println("### Iteration " + i + " ###");
ClassLoader classLoader = new URLClassLoader(urls) {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
final Class<?> loadedClass;
if ( "DummyClass".equals(name) ) {
System.out.println (this + " - finding class " + name);
loadedClass = findClass(name);
System.out.println (this + " - loading class " + loadedClass);
} else {
// delegate to parent
loadedClass = this.getParent().loadClass(name);
}
return loadedClass;
}
};
classLoaders.add(classLoader);
classLoader.loadClass("DummyClass");
System.out.println("Total: " + loadingMXBean.getTotalLoadedClassCount());
System.out.println("Active: " + loadingMXBean.getLoadedClassCount());
System.out.println("Unloaded: " + loadingMXBean.getUnloadedClassCount());
}
} catch ( Exception ex ) {
ex.printStackTrace();
}
}
}
运行 -XX:MaxMetaspaceSize=100m
,我终于明白了:
> ### Iteration 16318 ###
> Test@531ed68e - finding class DummyClass
> Test@531ed68e - loading class class DummyClass
> Total: 16747 Active:
> 16747 Unloaded: 0
> ### Iteration 16319 ###
> Test@6bbd4048 - finding class DummyClass
> Exception in thread "main" java.lang.OutOfMemoryError: Metaspace at
> java.lang.ClassLoader.defineClass1(Native Method) at
> java.lang.ClassLoader.defineClass(ClassLoader.java:756) at
> java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
> at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) at
> java.net.URLClassLoader.access0(URLClassLoader.java:74) at
> java.net.URLClassLoader.run(URLClassLoader.java:369) at
> java.net.URLClassLoader.run(URLClassLoader.java:363) at
> java.security.AccessController.doPrivileged(Native Method) at
> java.net.URLClassLoader.findClass(URLClassLoader.java:362) at
> Test.loadClass(Test.java:42) at Test.main(Test.java:53)
我有一个任务是故意模拟 OutOfMemory: Metaspace 错误。我尝试了不同的方法,但 none 给了我需要的结果。有人可以为此分享好的例子吗?
我的第一次尝试(使用 javassist):
static ClassPool classPool = ClassPool.getDefault();
@SneakyThrows
public void task() {
try {
for (int i = 0; ; i++) {
Class cl = classPool.makeClass("task1.Test" + i).toClass();
}
} catch (Error er) {
Runtime.getRuntime().gc();
log.error(er.getMessage());
}
}
和 gradle.properties 文件中的设置:
org.gradle.jvmargs=-XX:MaxMetaspaceSize=70M
但是我有一个错误:
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
我没听清楚。
我的第二次尝试:
public void task() {
try {
URL url = new File("D:/classes").toURI().toURL();
URL[] urls = {url};
ClassLoadingMXBean loadingMXBean = ManagementFactory.getClassLoadingMXBean();
List<ClassLoader> classLoaders = new ArrayList<>();
while (true) {
ClassLoader classLoader = new URLClassLoader(urls);
classLoaders.add(classLoader);
classLoader.loadClass("test1.Test1");
log.info("Total: " + loadingMXBean.getTotalLoadedClassCount());
log.info("Active: " + loadingMXBean.getLoadedClassCount());
log.info("Unloaded: " + loadingMXBean.getUnloadedClassCount());
}
} catch (Exception ex) {
log.error(ex + ex.getMessage());
}
}
没用,IDEA告诉我内存有规律
您忘记了 class加载在 JVM 中的工作方式。 classloader 将首先尝试让其父加载您要查找的 class。为了让你的测试工作,你需要一个自定义 class 加载器,它不会为你正在测试的 class 委托给它的父级。
这是一个适用于 Java 8
的示例DummyClass.java(默认包)
public class DummyClass {
static String padding = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
}
Test.java(默认包)
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
try {
URL url = Test.class.getResource("").toURI().toURL();
System.out.println("URL = " + url);
URL[] urls = {url};
ClassLoadingMXBean loadingMXBean = ManagementFactory.getClassLoadingMXBean();
List<ClassLoader> classLoaders = new ArrayList<>();
System.out.println("Total: " + loadingMXBean.getTotalLoadedClassCount());
System.out.println("Active: " + loadingMXBean.getLoadedClassCount());
System.out.println("Unloaded: " + loadingMXBean.getUnloadedClassCount());
int i = 0;
while ( true ) {
i++;
System.out.println("### Iteration " + i + " ###");
ClassLoader classLoader = new URLClassLoader(urls) {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
final Class<?> loadedClass;
if ( "DummyClass".equals(name) ) {
System.out.println (this + " - finding class " + name);
loadedClass = findClass(name);
System.out.println (this + " - loading class " + loadedClass);
} else {
// delegate to parent
loadedClass = this.getParent().loadClass(name);
}
return loadedClass;
}
};
classLoaders.add(classLoader);
classLoader.loadClass("DummyClass");
System.out.println("Total: " + loadingMXBean.getTotalLoadedClassCount());
System.out.println("Active: " + loadingMXBean.getLoadedClassCount());
System.out.println("Unloaded: " + loadingMXBean.getUnloadedClassCount());
}
} catch ( Exception ex ) {
ex.printStackTrace();
}
}
}
运行 -XX:MaxMetaspaceSize=100m
,我终于明白了:
> ### Iteration 16318 ###
> Test@531ed68e - finding class DummyClass
> Test@531ed68e - loading class class DummyClass
> Total: 16747 Active:
> 16747 Unloaded: 0
> ### Iteration 16319 ###
> Test@6bbd4048 - finding class DummyClass
> Exception in thread "main" java.lang.OutOfMemoryError: Metaspace at
> java.lang.ClassLoader.defineClass1(Native Method) at
> java.lang.ClassLoader.defineClass(ClassLoader.java:756) at
> java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
> at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) at
> java.net.URLClassLoader.access0(URLClassLoader.java:74) at
> java.net.URLClassLoader.run(URLClassLoader.java:369) at
> java.net.URLClassLoader.run(URLClassLoader.java:363) at
> java.security.AccessController.doPrivileged(Native Method) at
> java.net.URLClassLoader.findClass(URLClassLoader.java:362) at
> Test.loadClass(Test.java:42) at Test.main(Test.java:53)