JVM虚拟机

作者: 汤姆torn | 来源:发表于2020-07-09 15:12 被阅读0次

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

    相关文章

      网友评论

        本文标题:JVM虚拟机

        本文链接:https://www.haomeiwen.com/subject/xpcscktx.html