JVM调优
javap查看底层代码执行逻辑
1.反编译class文件:javap -c xxx.class > 目标文件名
Compiled from "Math.java"
public class classdiceng.Math {
public classdiceng.Math();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class classdiceng/Math
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: invokevirtual #5 // Method computer:()I
15: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
18: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
21: ldc #7 // String test
23: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
26: return
public int computer();
Code:
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: bipush 10
9: imul
10: istore_3
11: iload_3
12: ireturn
}
gc 回收
- .minor gc只回收年轻代, 采用可达性分析算法 gc roots向下找,直到最后一个,这些标记为非垃圾,其余就为垃圾分代年龄达到15进入老年代(不同垃圾收集器分代年龄可能不同)
- full gc 回收整个堆内存 老年代满了之后并不会直接oom,而是先full gc,回收不了,满了。oom
可作为gc roots的有
- 虚拟机栈(局部变量表中引用的对象)
- 本地方法栈(本地方法引用的对象)
- 方法区中静态属性引用的对象
- 方法区中静态常量池中引用的对象
老年代:2/3
eden:s0:s1=8:1:1
jvm调优工具
jdk自带调优命令 jvisualvm
Alibaba Arthas
- 下载arthas https://arthas.aliyun.com/arthas-boot.jar
- java -jar arthas-boot.jar并启动测试程序
- 命令
dashboad # 监控本地java线程,找出异常线程
thread 线程id # 定位异常线程代码行
测试代码
public class Test1 {
public static void main(String[] args) {
while (true){
}
}
}
dashboard发现线程id=1占用cpu过高
thread 1
可以看到代码第五行异常:原来室友while true 死循环
常用命令
dashboard # 线程实时监控
thread 线程id # 查看线程具体信息
jad java类 # 反编译java代码
调优实战分析
调优目的
减少gc尤其是full gc,就是减少STW(stop the word)因为gc时,会停掉用户线程,不同垃圾回收器STW实现不一样
为什么要有STW机制
假设没有stw,gc时用户线程不会暂停,在根据gc roots 可达性分析算法查找垃圾时,有些对象不是垃圾, 然后查找其他变量的垃圾对象,没有stw,假设gc线程还没有结束,用户线程已经结束,局部变量就没有了,就没有引用了,就没有垃圾了。但gc之前找到了垃圾,矛盾了,难道要重新找一次?
案例
案例1:是否可以几乎不发送full gc ?
场景:高并发项目,每秒60M,超过了s区的一般,有可能直接进去老年代,这样过个几分钟老年代就满了,j就触发full gc,要调优
其实:每秒60M的数据进入老年代,其实它刚进入老年代不就,它就是是垃圾了,但minor Gc无法回收老年代
优化策略:年轻代内存分配大一些,老年代小一些
案例2
案例1基础上,如果是单机几十万的高并发项目,想kafka,mq,怎么样调优?
首先,内存,cpu肯定要大,这样,堆内存就分的大。像这样,
但是,问题是。eden满时,触发minor gc,但eden是30G,minor gc时间会过长,怎么解决?
解决思想:如果能使eden表边gc边使用,就是每次回收只回收一部分,就使STW短了,用户体验好,而不是回收全部eden,这样新来的对象就可以放在回收后的一部分eden中,就像自定义minor gc触发,G1垃圾收集器就是这样,设置MaxGCPauseMillis定义minor gc回收时间