java8中使用Metaspace就不会出现OOM吗?

Java8引入Metaspace替代了 PermGen,减少了OOM问题,但并非完全消除。Metaspace默认受本地内存限制,可通过设置MaxMetaspaceSize控制。实验表明,未设置限制时,Metaspace可动态扩展导致300M本地内存使用;当限制为128M时,会引发OOM。无限制使用可能导致系统被OS强制关闭,建议设定合理上限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:在java8中,Metaspace的出现,使我们现在不会再遇到java.lang.OutOfMemoryError: PermGen问题,但是我们要记住,这个新特性并不会使类加载导致的内存泄露就此消失。

(一)Metaspace的简单介绍
(1)内存模型:大部分类元数据都在本地内存分配,用于描述类元数据的“klasses“已经被移除。
(2) 容量:默认情况下只受本地内存限制,但是我们可以限制。

(二)接下来看看Metaspace会不会出现OOM
我们可以通过动态代理来生成大量的代理类信息填充元数据区。代码如下

public interface MetaspaceFacade {
    void method(String input);
}
public class MetaspaceFacadeImpl implements MetaspaceFacade {

    public void method(String name) {
    }
}
public class MetaspaceFacadeInvocationHandler implements InvocationHandler {

    private Object classAImpl;

    public MetaspaceFacadeInvocationHandler(Object impl) {
       this.classAImpl = impl;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

       return method.invoke(classAImpl, args);
    }
}
public class ClassMetadataLeakSimulator {

    private static Map<String, MetaspaceFacade> classLeakingMap = new HashMap<String, MetaspaceFacade>();
    private final static int NB_ITERATIONS_DEFAULT = 50000;

    /**
     * @param args
     */
    public static void main(String[] args) {

        System.out.println("Class metadata leak simulator");

        int nbIterations = NB_ITERATIONS_DEFAULT;

        try {

            for (int i = 0; i < nbIterations; i++) {

                String fictiousClassloaderJAR = "file:" + i + ".jar";

                URL[] fictiousClassloaderURL = new URL[] { new URL(fictiousClassloaderJAR) };

                URLClassLoader newClassLoader = new URLClassLoader(fictiousClassloaderURL);

                MetaspaceFacade t = (MetaspaceFacade) Proxy.newProxyInstance(newClassLoader,
                        new Class<?>[] { MetaspaceFacade.class },
                        new MetaspaceFacadeInvocationHandler(new MetaspaceFacadeImpl()));

                classLeakingMap.put(fictiousClassloaderJAR, t);
            }
        } 
        catch (Throwable any) {
            System.out.println("ERROR: " + any);
        }

        System.out.println("Done!");
    }
}

1,首先不进行任何设置(需要保证堆大小),运行得到下面的截图
这里写图片描述
可以看出,Metaspace进行了动态扩展,本地内存达到了300多M,加载超过5万个类后还没有出现OOM事件。接下来我们限定一下

2,虚拟机参数配置如下:-Xmx2g -Xms2g -Xmn1g -XX:+PrintGCDetails -XX:MaxMetaspaceSize=128m,运行得到下面的截图
这里写图片描述
可以看出,此时Metaspace被耗尽,将会抛出OOM事件。这里要注意MaxPermSize的区别,MaxMetaspaceSize并不会在jvm启动的时候分配一块这么大的内存出来,而MaxPermSize是会分配一块这么大的内存的。

那么问题来了,如果我们不设置MaxMetaspaceSize,那么我们能用到系统的全部内存吗??
metaspace很可能因为被无止境使用而被OS Kill,所以一般还是设置比较好。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值