JVM是Java Virtual Machine(Java虚拟机)的缩写。
Java虚拟机主要分为五大模块:类装载器子系统、运行时数据区、执行引擎、本地方法接口和垃圾收集模块。
而为主要的,经常被问起的,就只有类装载器子系统、运行时数据区和垃圾收集模块。
一.类装载机制
这个要了解,类加载机制的具体流程,和流程都做了什么。
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中验证、准备、解析3个部分统称为连接(Linking)。
a.加载:就是加载.class文件,这中间做了三件事,
1.通过类的全限定名获取相应的二进制字节流。
2.将字节流代表的静态存储结构化为方法区的运行时数据结构。
3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
b.验证
1.文件格式验证,验证class文件的版本号是否可处理
2.元数据验证,验证java语言规范
3.字节码验证
4.符号引用验证
c.准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(static 修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在java堆中。
准备阶段的分配仅仅是分配内存空间,值还是默认的。例如
public static int num=1;
准备阶段之后 num值0,准备阶段只是分配空间。
d.解析
解析阶段是虚拟机常量池内的符号引用替换为直接引用的过程。
e.初始化
类的初始化阶段是类加载过程的最后一步,在准备阶段,类变量已赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员通过程序制定的主观计划去初始化类变量和其他资源。
二.运行时数据区(JVM内存区域)
分别为堆,栈,元空间(1.7叫方法区/永久代)
a.堆(线程共享)
对象实例几乎都在这,也是垃圾回收主要发生的地方。
堆的划分:
1.新生代:(1/3)
Eden 区(初始对象在这,98%的对象需要回收),Survivor区(from,to两块);
eden : from:to默认比例8:1:1,from和to两者同时只有一个有数据,
YongGC使用复制回收算法--eden 和Survivor from(有值的区域)存活数据复制到to(空的),存活一次,年龄+1,存活到15晋级老年代(或者某个年龄的数据量达到50%触发提前晋级)
2.老年代(2/3)
数据来源:新生代数据晋级过来的(提前晋级或正常晋级);数据过大,直接分配在老年代
FullGC
虚拟机配置
-Xms256m 初始堆大小
-Xmx512m 堆最大
-Xmn80m 新生代大小
-Xss 每个线程大小(默认1M,基本不用管,够用)
–XX:NewRatio=2 新生代与老年代的比例,老年代:新生代,新生代占三分之一
-XX:SurvivorRatio=8 新生代Eden与Survivor from to 比例,eden:from:to 8:1:1
b.栈(线程独享,内部是一个个的栈帧,每个栈帧都是一个方法)
划分:
1.虚拟机栈,每个线程私有的,线程在运行时,在执行每个方法的时候都会打包成一个栈帧,存储了局部变量表,操作数栈,动态链接,方法出口等信息,然后放入栈。每个时刻正在执行的当前方法就是虚拟机栈顶的栈桢。方法的执行就对应着栈帧在虚拟机栈中入栈和出栈的过程。
2.本地方法栈,本地方法
3.程序计数器 ,记录程序运行到哪了,线程切换
c.元空间(1.8之后,之前是永久代)
用于存储已经被虚拟机加载的类信息,常量("zdy","123"等),静态变量(static变量)等数据,可用以下参数调整:
jdk1.7及以前:-XX:PermSize;-XX:MaxPermSize;
jdk1.8以后:-XX:MetaspaceSize; -XX:MaxMetaspaceSize