程序员

JVM虚拟机

2020-07-09  本文已影响0人  汤姆torn

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 设置元空间最大值
上一篇 下一篇

猜你喜欢

热点阅读