02-VIP-JVM内存模型深度剖析与优化.pdf
不断的在栈帧里面往上创建栈帧内存空间,一个方法对应于一个栈帧内存空间,栈帧先进后出(数据结构中的栈)
为何用这个栈?
先调用main方法,先给main方法分配内存空间,再调用computer方法,再给computer分配内存空间,但是computer方法后调用,程序的执行顺序是后调用的先执行,执行完了再回到main方法,局部方法执行完,对应的局部变量的内存空间都要释放掉(comouter方法对应的栈帧内存空间释放掉,就是出栈,就是被消费掉,体现出后进来的先被消费掉),后调用的方法反而先执行完

iconst_1 将int类型常量1压入操作数栈
istore_1 将int类型值存入局部变量1
iconst_2 将int类型常量1压入操作数栈
istore_2 将int类型值存入局部变量2
iload_1 从局部变量1中装载int类型值 ——将1放入操作数栈
iload_2 从局部变量1中装载int类型值 ——将2放入操作数栈
iadd 执行int类型的加法 —-将操作数栈数据1,2拿出来做加法结果3重新压入操作数栈
bipush 将一个8位带符号整数压入栈 ——将10放入操作数栈
imul 执行int类型的乘法 —-将操作数栈数据3,10拿出来做乘法结果30重新压入操作数栈
istore_3 将int类型值存入局部变量3 ——给c赋值,在局部变量表中c分配内存空间,然后将30出栈,分配到c内存空间去
iload_3 从局部变量3中装载int类型值 ——将30放入操作数栈
ireturn 从方法中返回int类型的数据 ——将值返回到主线程中
————————————————————————————————————————————————————————-
局部变量表:
操作数栈:在程序运行过程中,将要进行操作的一块临时中转存放(变量的值)的内存空间;
动态连接:把符号引用转为直接引用。在程序运行过程中,把符号引用转换为符号对应的比如computer方法对应的代码的内存地址,说白了就是符号直接引用。
方法出口:根据方法出口的信息,知道返回main方法里面继续从哪一行代码执行
程序计数器
字节码执行引擎最终要把Math.class类加载到方法区,而程序计数器就是计的代码执行的位置(多线程,假设正在执行的线程处在上图4的位置,被优先级更高的线程把我们cpu的时间片给抢占过去了,当前线程就处于挂起状态,将来是不是要恢复,告诉cpu上一次执行的代码位置,由程序计数器提供)
在执行每一行代码时,都会修改程序计数器中对应的位置
堆:
如果老年代放满了,不会马上触发OOM,会先触发full gc,和young gc类似,只是回收的是整个堆,还有方法区,然后会发现堆里面老年代对象还是被gc root所引用,所以回收不了,导致老年代没有回收空间给新的对象放了,触发OOM
SWT机制:在full gc 或者young 过程中,会触发SWT机制(停止整个事件),停止用户线程(young 过程中,SWT时间非常短几乎可以忽略不计;在full gc 过程中,因为full gc过程相对比较长,所以对应的SWT时间也会比较长,SWT会导致用户感知到系统的卡顿,体验感不好)
jvm调优,最主要的就是减少full gc或者说减少一次full gc的执行时间,当然young gc比较频繁,也应该减少young gc次数。
面试题:JVM为何要设置SWT机制?可以不做么,也就是说让用户线程继续下单,继续加购物车不行么
在GC过程中,为何要SWT,在GC过程中,无非就是找垃圾回收对象,比如之前发生了full gc了,在这边通过gc root找一个链条上的对象,找完了,正准备找其他的,还有其他的gc root对象,还没有找完,因为没有SWT机制(取消了SWT机制),虽然在做gc,用户线程可以继续去执行,用户线程结束了,意味着这些局部变量出栈了,被释放掉了,只要线程结束,那些栈内存空间都被消费掉,那会意味着什么,意味着通过上面的gc root对象(不存在了)找到的相关链条上的对象已经变成垃圾对象了,你之前认为是非垃圾对象,现在gc还没有结束,又变成垃圾对象了,那这还得了,那堆里面几十万上百万的对象,之前做的gc过程,不都白做了么 。说白了,我们整个JVM内部针对于这种情况,收集完堆里面对象以后不确定,难道要再次再遍历一次看堆里面对象是否为垃圾对象么,那太复杂了,所以JVM在这个过程中,索性在做gc的时候,一些核心的步骤,找对象的过程中,触发SWT机制,用户线程先不变动,我找出了对象,当我要结束的时候,他就不是垃圾对象,给赋值到Survivor区中。

