如何模拟OutOfMemoryError:元空间

时间:2018-10-05 08:48:00

标签: java

我想知道如何自行导致OutOfMemoryError:Metaspace异常?是否可以加载很多类并使它们在内存中保留很长时间。

3 个答案:

答案 0 :(得分:1)

只需继续将一些文本附加到StringBuilder,直到获得OutOfMemoryError

StringBuilder s = new StringBuilder();

while (true) {
    s.append("dummy");
}

您还可以在ListSet上添加一些虚拟类,但是创建新实例比较耗时,并且必须等待一段时间才能获得OutOfMemoryError

插入数组列表的摊销时间成本也将有所不同。

已更新

默认情况下,Java 8对Metaspace的最大大小没有限制,因此,只要您不使用MaxMetaspaceSize标志来设置限制,就不应引发错误。

答案 1 :(得分:0)

要创建OutOfMemoryError: Metaspace,请使用javassist.ClassPool库。以下示例将创建Metaspace错误。

import javassist.ClassPool;

public class OutOfMemoryErrorMetaspace {

    //ClassPool objects hold all the CtClasses.
    static ClassPool classPool = ClassPool.getDefault();

    public static void main(String[] args) throws Exception {
           for (int i = 0; i < 1000000; i++) {
                  //makeClass method - Creates a new class (or interface) from the given class file.
                  Class clas = classPool.makeClass(
                               i + " outofmemory.OutOfMemoryErrorMetaspace ").toClass();
                  //Print name of class loaded
                  System.out.println(clas.getName());
           }
    }
}

答案 2 :(得分:0)

为了模拟java.lang.OutOfMemoryError: Metaspace,您必须加载许多不同的类。

首先必须设置以下元空间设置:

-XX:MaxMetaspaceSize=10m
-XX:MetaspaceSize=2M
-XX:MaxMetaspaceFreeRatio=1
-XX:MaxMetaspaceExpansion=1K
-XX:MinMetaspaceFreeRatio=1
-XX:InitialBootClassLoaderMetaspaceSize=2M

然后下面的代码使类加载器加载许多不同的类。 这是通过获取类mypackage.Myclass0的已编译字节码并通过更改类名和调整类名的长度来调整以迭代方式创建新类来实现的:

    public static void main(String[] args) throws Exception {
        String clazzBase64 ="yv66vgAAADcADAEAEm15cGFja2FnZS9NeWNsYXNzMAcAAQEAEGphdmEvbGFuZy9PYmplY3QHAAMBAApTb3VyY2VGaWxlAQANTXljbGFzczAuamF2YQEABjxpbml0PgEAAygpVgwABwAICgAEAAkBAARDb2RlACEAAgAEAAAAAAABAAEABwAIAAEACwAAABEAAQABAAAABSq3AAqxAAAAAAABAAUAAAACAAY=";

        byte[] compiledClazz = Base64.getDecoder().decode(clazzBase64);
        int classNameLength = Integer.valueOf(compiledClazz[12]);

        MyClassLoader myClassLoader = new MyClassLoader(Thread.currentThread().getContextClassLoader());

        for (int i = 0; ; i++) {
            byte[] bytes = String.valueOf(i).getBytes();
            byte[] bytecode = new byte[compiledClazz.length + bytes.length - 1];
            System.arraycopy(compiledClazz, 0, bytecode, 0, 30);
            bytecode[12] = (byte) (classNameLength + bytes.length - 1 & 0xFF);

            System.arraycopy(bytes, 0, bytecode, 30, bytes.length);
            System.arraycopy(compiledClazz, 31, bytecode, 30 + bytes.length, compiledClazz.length - 31);

            String classname = "mypackage.Myclass" + i;
            Class c = myClassLoader.getClass(classname, bytecode);
        }
    }

    public static class MyClassLoader extends ClassLoader {
        public MyClassLoader(ClassLoader parent) {
            super(parent);
        }

        public Class<?> getClass(String name, byte[] code) {
            return defineClass(name, code, 0, code.length);
        }
    }