Jdk8以后为什么改用元空间来实现方法区
方法区的演进
Jdk7及以前:永久代实现
jdk8开始:元空间实现(用的是本地物理内存,因此元空间的限制可以不受JVM的内存限制,决定于物理内存)
Jdk7及以前:
初始化值默认为20.75M,32位机最大值为64M,64位最大值为82M
Jdk8及以后:
查看元空间大小的命令:
jinfo -flag MetaspaceSize 95560
jinfo -flag MaxMetaspaceSize 95560
设置元空间大小命令:
-XX:MetaspaceSize=100m -XX:MaxMetaspaceSize=100m
- 1、一般而言,方法区不用设置最大空间限制,只设置初始化大小MetaspaceSize
- 2、MetaspaceSize是动态变化的,一旦触及这个水位线,就会触发一次FullGC,若释放的元空间不多,则适当调高这个值;若释放空间很多,则适当降低该值;为了避免频繁FullGC,MetaspaceSize一般需要设置为一个相对较高的值;
方法区的内部结构:
- 1、《深入理解Java虚拟机》描述经典方法区:存储已被虚拟机加载的类信息、运行时常量池、静态变量、即时编译器编译后的代码缓存等。
- 2、class文件载入到方法区后,才会有ClassLoader对象,反编译class文件:javap -v -p HelloWorld.class >test.txt
- 3、Class文件加载到方法区后的模样:参考《自己动手写Java虚拟机》:
类信息:
字段信息:
方法信息:
运行时常量池:
- 符号引用:Constant classRef,methodRef ,fieldRef, consts[n]={classRef,methodRef ,fieldRef},通过索引访问
- 直接引用:classRef=*student,fieldRef=*name,methodRef=*main()
方法区的使用示例与理解:
public class Student{
private static int id=11;
private String name;
private final int age=9;
public static void main(String[] args) {
int a=1;
int b=2;
System.out.println(a+b);
}
}
加载(准备材料)——执行(main方法开始)
串联一下前面的类加载的内容,解释一下只有Class文件运行时从加载到执行的过程:
- 1、我们前面说类加载时Class文件经历了加载、链接(校验、准备置零、解析符号引用)、初始化静态变量的阶段;
- 2、经历完这些阶段后,方法区中也就新建好Student类、字段、方法信息、把Class文件的常量池解析为运行时常量池(consts[n]),并创建一个Student类的Class对象,同时初始化好静态变量,并把运行时常量池中的符号引用转为直接引用;
- 3、前两步为准备材料阶段,接下来便会从main()方法开始执行方法的命令;