欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: 五月的仓颉

被废弃的耐久代

想起之前口试的时候有口试官问起过我一个问题:Java 8为什么要废弃耐久代即Metaspace的浸染。由于其时利用的Java 7且研究重心不在JVM上,一下没有答复上来,本日溘然想起这个问题,就具体总结一下这个问题。

首先我们看一张JVM内存机关的图:

在Java 6及之  <a href=苏州软件定制开拓 前的版本" src="http://www.importnew.com/https:/images2018.cnblogs.com/blog/801753/201804/801753-20180401164846766-809607195.png" />

留意到内里有一块METHOD AREA,它是一块线程共享的工具,昆山软件开发,名为要领区,在HotSpot虚拟机中,这块METHOD AREA我们可以认为等同于耐久代(PermGen),在Java 6及之前的版本,耐久代存放了以下一些内容:

  • 虚拟机加载的类信息
  • 常量池
  • 静态变量
  • 即时编译后的代码
  • 到了Java 7之后,常量池已经不在耐久代之中举办分派了,而是移到了堆中,即常量池和工具共享堆内存。

    接着到了Java 8之后的版本(至此篇文章,Java 10刚宣布),耐久代已经被永久移除,取而代之的是Metaspace。

    为什么要移除耐久代

    HotSpot团队选择移除耐久代,有内因和外因两部门,从外因来说,我们看一下JEP 122的Motivation(念头)部门:

    This is part of the JRockit and Hotspot convergence effort. JRockit customers do not need to configure the permanent generation (since JRockit does not have a permanent generation) and are accustomed to not configuring the permanent generation.

    大抵就是说移除耐久代也是为了和JRockit举办融合而做的尽力,JRockit用户并不需要设置耐久代(因为JRockit就没有耐久代)。

    从内因来说,耐久代巨细受到-XX:PermSize和-XX:MaxPermSize两个参数的限制,劳务派遣管理系统,而这两个参数又受到JVM设定的内存巨细限制,这就导致在利用中大概会呈现耐久代内存溢出的问题,因此在Java 8及之后的版本中彻底移除了耐久代而利用Metaspace来举办替代。

    Metaspace

    上面说了,为了制止呈现耐久代内存溢出的问题,Java 8及之后的版本彻底移除了耐久代而利用Metaspace来举办替代。

    Metaspace是要领区在HotSpot中的实现,它与耐久代最大的区别在于:Metaspace并不在虚拟机内存中而是利用当地内存。因此Metaspace详细巨细理论上取决于32位/64位系统可用内存的巨细,昆山软件公司,可见也不是无限制的,需要设置参数。

    接着我们模仿一下Metaspace内存溢出的环境,前面说了耐久代存放了以下信息:

  • 虚拟机加载的类信息
  • 常量池
  • 静态变量
  • 即时编译后的代码
  • 所以最简朴的模仿Metaspace内存溢出,我们只需要无限生成类信息即可,类占据的空间老是会高出Metaspace指定的空间巨细的,下面用Cglib来模仿:

    public class MetaspaceOOMTest {
    
        /**
         * JVM参数:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=128m -XX:+PrintFlagsInitial
         */
        public static void main(String[] args) {
            int i = 0;
            
            try {
                for (;;) {
                    i++;
                    
                    Enhancer enhancer = new Enhancer();
                    enhancer.setSuperclass(OOMObject.class);
                    enhancer.setUseCache(false);
                    enhancer.setCallback(new MethodInterceptor() {
                        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                            return proxy.invokeSuper(obj, args);
                        }
                    });
                    enhancer.create();
                }
            } catch (Exception e) {
                System.out.println("第" + i + "次时产生异常");
                e.printStackTrace();
            }
        }
        
        static class OOMObject {
            
        }
        
    }

    虚拟机参数配置为”-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=128m“,运行代码,功效为:

    第15562次时产生异常
    net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
        at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345)
        at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)
        at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:114)
        at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
        at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
        at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305)
        at org.xrq.commom.test.jvm.MetaspaceOOMTest.main(MetaspaceOOMTest.java:34)
    Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:413)
        at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336)
        ... 6 more
    Caused by: java.lang.OutOfMemoryError: Metaspace
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        ... 11 more

    可见纵然利用了Metaspace,也是有OOM的风险的,可是由于Metaspace利用本机内存,因此只要不要代码内里犯太初级的错误,OOM的概率根基是不存在的。

    Metaspace相关JVM参数