最近面了两家公司连续被问到 JDK 1.7 和 1.8 在内存方面的变化,没能回答得很好,总结一下

97 阅读4分钟

前言

最近去到一家公司A面试,被面试官问及jdk 1.7和1.8在内存方面的变化,起初只记得1.7有“永久代”,1.8废弃了“永久代”,使用“方法区”代替,但是具体里面的细节,没有深入研究过,因此没能给面试官一个完美的回答;面完后,抱着侥幸的心理,觉得面试官可能随意一问,且这个知识点感觉不是特别的热门,就没有特意下功夫去研究一下细节。没想到隔天去到公司B面试,又被面试官问到相同问题,心里不禁一阵后悔,为什么昨天没有好好整理一下,不然就可以侃侃而谈了;因此,决心整理一下这个知识点,再有下次被问及,一定要能够回答得上来;

最近一直在本奔波长沙地区的面试,感受到了大环境下java后端行情确实下滑严重,薪资削减太多了;没收割到心仪的offer,在一次次面试中,都被面试官问及到没深入研究过的知识点,给面试官一种不好的印象,心态也会受到一点影响,会有点摆烂的心理在里面,觉得运气成分在面试中占很大的运气;但是昨晚无意间,刷到一个求职者的抖音,他说过一句话对我感触很深,说“面试中对面试官的提问回答不上来,面完后做知识整理,回头填补到简历上,将劣势变成自己的优势”,我觉得他的心态比我积极多了,跟这种求职者竞争,我肯定是劣势,因此决心向他学习,及时整理欠缺的知识点,将劣势化为优势;

最后借鉴马云的一句话,感觉适用于当下惨淡的互联网环境,“今天很残酷,明天更残酷,后天会很美好,但绝大多数人都死在了明天晚上,却见不到后天的太阳,所以我们干什么都要坚持”。

知识梳理

备注下:由于网上博客各种说法都有,且没有附上依据,我一时不知道谁对谁错。所以以下总结均是在《深入理解Java虚拟机》.pdf上找到的内容,如有错误,一定要帮忙指正下,保证知识点的准确性。

jdk 1.7 运行时数据区

运行时数据区图,仅针对不同之处做详细说明

image.png

永久代存的信息以及堆中存放信息,可以查看相关文献《深入理解Java虚拟机》

image.png

上文其实核心点如下:

  • JDK7 永久代分配在堆内存当中,可通过-XX:MaxPermSize来设置
  • 类信息存储在永久代,其余的常量值、静态变量存于堆空间

jdk 1.8 运行时数据区

运行时数据区图,仅针对不同之处做详细说明

image.png

上文其实核心点如下:

  • JDK8 移除了永久代,新增了方法区,且方法区不再占用堆内容,而是使用的直接内存
  • 常量值、静态变量、类信息存于方法区

实际验证

以上内容可能均来自文献,程序员讲究实践出真知,那我们就来实际写代码,验证下呗

背景:
我们模拟cglib产生大量类,类信息是存在jdk 1.7 永久代、jdk 1.8方法区内的,我们分别设置不同的启动参数,让其占满对应的区域,产生异常,验证不同的jdk版本,有不同的区域存在。

  • 首先添加pom依赖
<dependencies>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-full</artifactId>
        <version>2.0.2</version>
    </dependency>
</dependencies>
  • 编写测试代码
package com.doudou.methodareaoom;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class Test {

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(DouDou.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {

                @Override
                public Object intercept(Object obj, Method arg1, Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, args);
                }
            });
            DouDou douDou = (DouDou) enhancer.create();
        }
    }

    static class DouDou {

    }

}
  • jdk1.7修改启动参数,设置初始元空间,以及最大元空间大小均为30M
-Xms6M
-Xmx6M
-XX:PermSize=30M
-XX:MaxPermSize=30M
  • 启动代码,观察控制台打印的异常,以及VisualVM关于永久代的内存占比情况

image.png

image.png

image.png

  • jdk1.8修改启动参数,设置初始方法区,以及最大方法区空间大小均为30M
-Xms6M 
-Xmx6M 
-XX:MetaspaceSize=30M 
-XX:MaxMetaspaceSize=30M
  • 启动代码,观察控制台打印的异常,以及VisualVM关于方法区的内存占比情况

image.png

image.png

image.png

总结

  • JDK7 永久代分配在堆内存当中,可通过-XX:MaxPermSize来设置
  • 类信息存储在永久代,其余的常量值、静态变量存于堆空间
  • JDK8 移除了永久代,新增了方法区,且方法区不再占用堆内容,而是使用的直接内存
  • 常量值、静态变量、类信息存于方法区