前言
最近去到一家公司A面试,被面试官问及jdk 1.7和1.8在内存方面的变化,起初只记得1.7有“永久代”,1.8废弃了“永久代”,使用“方法区”代替,但是具体里面的细节,没有深入研究过,因此没能给面试官一个完美的回答;面完后,抱着侥幸的心理,觉得面试官可能随意一问,且这个知识点感觉不是特别的热门,就没有特意下功夫去研究一下细节。没想到隔天去到公司B面试,又被面试官问到相同问题,心里不禁一阵后悔,为什么昨天没有好好整理一下,不然就可以侃侃而谈了;因此,决心整理一下这个知识点,再有下次被问及,一定要能够回答得上来;
最近一直在本奔波长沙地区的面试,感受到了大环境下java后端行情确实下滑严重,薪资削减太多了;没收割到心仪的offer,在一次次面试中,都被面试官问及到没深入研究过的知识点,给面试官一种不好的印象,心态也会受到一点影响,会有点摆烂的心理在里面,觉得运气成分在面试中占很大的运气;但是昨晚无意间,刷到一个求职者的抖音,他说过一句话对我感触很深,说“面试中对面试官的提问回答不上来,面完后做知识整理,回头填补到简历上,将劣势变成自己的优势”,我觉得他的心态比我积极多了,跟这种求职者竞争,我肯定是劣势,因此决心向他学习,及时整理欠缺的知识点,将劣势化为优势;
最后借鉴马云的一句话,感觉适用于当下惨淡的互联网环境,“今天很残酷,明天更残酷,后天会很美好,但绝大多数人都死在了明天晚上,却见不到后天的太阳,所以我们干什么都要坚持”。
知识梳理
备注下:由于网上博客各种说法都有,且没有附上依据,我一时不知道谁对谁错。所以以下总结均是在《深入理解Java虚拟机》.pdf上找到的内容,如有错误,一定要帮忙指正下,保证知识点的准确性。
jdk 1.7 运行时数据区
运行时数据区图,仅针对不同之处做详细说明
永久代存的信息以及堆中存放信息,可以查看相关文献《深入理解Java虚拟机》
上文其实核心点如下:
- JDK7 永久代分配在堆内存当中,可通过-XX:MaxPermSize来设置
- 类信息存储在永久代,其余的常量值、静态变量存于堆空间
jdk 1.8 运行时数据区
运行时数据区图,仅针对不同之处做详细说明
上文其实核心点如下:
- 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关于永久代的内存占比情况
- jdk1.8修改启动参数,设置初始方法区,以及最大方法区空间大小均为30M
-Xms6M
-Xmx6M
-XX:MetaspaceSize=30M
-XX:MaxMetaspaceSize=30M
- 启动代码,观察控制台打印的异常,以及VisualVM关于方法区的内存占比情况
总结
- JDK7 永久代分配在堆内存当中,可通过-XX:MaxPermSize来设置
- 类信息存储在永久代,其余的常量值、静态变量存于堆空间
- JDK8 移除了永久代,新增了方法区,且方法区不再占用堆内容,而是使用的直接内存
- 常量值、静态变量、类信息存于方法区