作者:钟剑华  历史版本:1  最后编辑:Eddy  更新时间:2024-06-19 18:08

编写版本:v3.3.7
适用版本:所有版本

Jvm介绍

  • JVM内存区域的划分,年轻代和老年代,他们都发生gc行为,对应young gc(ygc)和full gc(fgc)

  • 年轻代-ygc,程序不会挂起

    eden-伊甸园,变量的出生地
    s0-幸存代0,
    s1-幸存代1,
    以上三个都是年轻代的区域,无论哪个满了都会发生ygc行为,
    eden是变量的出生地,发生ygc就会把还存在引用的变量转移到s0或s1,同时变量还有个类似年龄的值加1
    s0或s1是变量的生活区,两者空间一样大,eden发生gc后的变量就转移到这里,但是两者有且只有一个在工作,
    每当发生ygc,无论当前区域是否满都会把所有变量转移到另一区域,幸存代的所有变量年龄加1,当年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中

  • 老年代-fgc,程序会挂起,等待gc完成
    老年代只有一个区域,满了就会发生fgc,因为fgc的过程中导致程序挂起,必须降低发生次数

JVM调试

JVM调试工具-jvisulVM

jvisualVM,jdk自带工具,位置在${JAVA_HOME}/bin下,服务器和本地都要安装jdk,注意jre不包含该工具,jdk环境变量JAVA_HOME需要设置好,jdk9及以上的需要另外下载

调试模式

远程调试模式有两种,jmx和jstat模式,jmx稍微麻烦点,但能可以在jvisualVm中看到CPU的使用情况

jstat模式简介:

  1. 服务器上需要安装jdk,并在jdk的bin目录下创建jstatd.all.policy文件,需要全局变量设置有JAVA_HOME
    文件内容如下:
    grant codebase “file:${java.home}/lib/tools.jar” {
    permission java.security.AllPermission “*”, “read,write”;
    };
  2. 在bin目录下执行以下命令,hostname填入服务器ip
    jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.3.240 &
    jstatd -J-Djava.security.policy=${JAVA_HOME}/bin/jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.3.220 &
  3. 启动jvisualVM,然后添加远程主机,输入服务器ip点击确定,最后选择目标应用

更加具体调试的信息请参考以下链接:
https://www.cnblogs.com/jhxxb/p/13279201.html

jmx模式简介:

  1. jvm启动添加参数”-Djava.rmi.server.hostname=192.168.3.220 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8050 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false”
  2. 启动jvisualVM,然后添加远程主机,输入服务器ip点击确定,右键主机添加JMX连接
  3. 双击”192.168.3.220:8050”进入应用监控界面

导出jvm Head Dump

jmap -dump:format=b,file=文件名.hprof 进程号
jmap -dump:format=b,file=business.20220104.hprof 899071

调试方式:控制变量法

通过执行同一段压力测试脚本,保持每次变量一致,然后改动一个内存参数,查看内存和gc时间的变化

  • 调试建议:
  1. eden区域一直都会ygc,所以eden和gc time的图形应该是山峰式波形;
  2. eden、s0、s1无论是哪个满了都会发生ygc,导致年轻代变量的年龄加一;
  3. s0和s1应该关注最大值和当前使用最大值,如果当前没有达到最大值,而老年代一直增加,说明gc过于频繁导致变量年龄过快增长,那需要检查年轻代空间过小或者事务过长导致;
  4. 老年代的full gc不应该很频繁甚至应该没有,每次发生的间隔最好以天为单位。

Jvm参数

以下是常用的参数,加在jar的运行命令中

性能参数

• -XX:NewRatio=2 新生代内存容量与老生代内存容量的比例
• -XX:SurvivorRatio=8 新生代eden和s0内存容量的比例,jdk8默认是3
• -Xms等价于-XX:InitialHeapSize初始化堆内存大小
• -Xmx等价于-XX:MaxHeapSize最大的堆内存大小
• -Xmn等价于-XX:NewSize=size设置初始的年轻代的大小

调试参数

• -XX:-CITime 打印消耗在JIT编译的时间
• -XX:ErrorFile=./hs_err_pid.log 保存错误日志或者数据到文件中
• -XX:HeapDumpPath=./java_pid.hprof 指定导出堆信息时的路径或文件名
• -XX:-HeapDumpOnOutOfMemoryError 当首次遭遇OOM时导出此时堆中相关信息
• -XX:-PrintGC 每次GC时打印相关信息
• -XX:-PrintGC Details 每次GC时打印详细信息
• -XX:-PrintGCTimeStamps 打印每次GC的时间戳

更详细参数请看以下链接:
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html