Java虚拟机学习笔记,基于JDK8(慢慢完善)
jvm架构图.png对象分配
堆内对象分配在对象分配时,JVM把TLAB作为首选,开发人员通过-XX:UserTLAB设置开启TLAB空间,TLAB空间非常小,占Eden区的1%,通过-XX:TLABWastrTargetPercent设置TLAB和Eden的百分比,一旦TLAB分类失败,JVM通过尝试加锁机制确保数据原子性,从而直接在Eden分配内存
垃圾收集
收集形式 | 收集区域 | 触发机制 |
---|---|---|
Minor/Young GC | 只是新生代的垃圾收集 | 年轻代空间不足时,仅当Eden满,幸存区满不出发GC,触发Young GC时会引起Stop the World |
Major/Old GC | 只是老年代的垃圾收集(只有CMS GC会有单独收集老年代的行为) | 出现 Major GC 经常伴随至少一次的Minor GC(Parallel Scavenge收集齐直接进行Major GC),如果Major GC后内存不足,就OOM |
Mixed GC | 收集整个新生代以及部分老年代 | |
Full GC | 收集整个java堆和方法区(G1) | ①调用System.gc(),不一定执行②老年代空间不足③方法区空间不足④通过Minor GC后进入老年代的平均大小大于老年代的可用内存⑤由Eden,S0向S1复制时,对象大小大于S1可用内存,将对象转存到老年代,且老年代的可用内存小于该对象大小 |
虚拟机栈
虚拟机栈里存放了运行时方法的栈帧,每个栈帧中包括有局部变量表(LA),操作数栈(OS),动态链接(DL),返回地址(RA)
局部变量表:
为什么静态方法中不能使用 this 关键字
编译报错
非static方法包含this局部变量
操作数栈
JAVA虚拟机的执行引擎是基于栈的执行引擎
主要用于保存计算中间结果,作为计算过程中临时的存储空间,32bit类型占1个栈深度,64bit类型占两个栈深度。byte,short,char.int都按int存储
public class OprandStack {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = a + b;
System.out.println(c);
}
}
OprandStack.png
动态链接:把运行时的符号引用转换为调用方法的直接引用,指向运行时的常量池
getstatic是引用字段到#4,#4又指向(#29和#30)。从图中可以看到,#29指向了#36、#30指向了(#37,#38),方法里使用了System.out.println,所以最后是调用了常量池里的方法。
早期绑定:编译期就可以确定,且运行期保持不变。
晚期绑定:在编译器无法确定下来,只能在程序运行期根据实际类型绑定相关方法。
public class ListTest {
public static void main(String[] args) {
Collection<Integer> list = new ArrayList<>();
list.add(3);
list.add(4);
list.add(5);
list.stream().forEach((a)-> System.out.println(a));
}
}
调用指令 | 作用 |
---|---|
invokestatic | 调用静态方法,解析阶段确定唯一方法版本 |
invokespecial | 调用<init>方法、父类及私有方法,解析阶段确定方法唯一版本 |
invokevirtual | 调用所有虚方法 |
invokeinterface | 调用接口方法 |
invokeddynamic | 动态解析出需要调用的方法,然后执行 |
前4条指令固化在虚拟机内部,方法的调用执行人为不可干预,invokeddynamic则是由用户确定方法版本,其中invokestatic和incokespecial调用的方法称为非虚方法,其余的(final除外)称为虚方法
反编译方法:找到class文件的位置,使用 javap -verbose/v 文件名
返回地址
存放调用该方法的pc寄存器的值,对应的下一条地址。如果方法正常结束,把返回地址返回给调用该方法的调用者。如果抛出异常,把异常返回调用方法。
public class ReturnAddress {
public void method1() {
classicmethod2();
try {
errormethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void classicmethod2() {
}
public void errormethod() throws InterruptedException {
Thread.sleep(100);
}
}
method1
method2,3
method3抛出异常,异常处理就是在4-8行出现异常,直接到16行return
JVM常用参数
参数 | 作用 |
---|---|
-Xss | 设置栈空间大小 |
-XX:PrintFlagsInitial | 查看所有参数默认值 |
-XX:printFlagsFinan | 查看参数最终值 |
-Xms | 初始堆空间内存(默认1/64) |
-Xmx | 最大空间内存(默认1/4) |
-XX:NewRatio | 配置新生代和老年代占比,默认1:2 |
-XX:SurvivorRatio | 设置新生代和S0/S1比例,官方说默认8:1:1,实际不是 |
-XX:MaxTenuringThreshold | 新生代到老年代的年龄阈值,默认15,因为只分配到了4个字节 |
-XX:+PrintGCDetails | 输出详细GC日志 |
-XX:HandlePromotionFailure | 是否设置空间分配担保 |
-XX:+DoEscapeAnalysis | 开启逃逸分析,未逃逸对象会在栈上分配 |
-XX:MetaspaceSize | 设置元空间大小 |
-XX:MaxMetaspaceSize | 设置元空间最大值 |
网友评论