Arthas
Arthas是Alibaba开元的Java诊断工具。采用命令行交互式模式,可以定位和诊断线上程序的问题。
Arthas的使用
- 下载
# github下载arthas
wget https://alibaba.github.io/arthas/arthas‐boot.jar
# 或者 Gitee 下载
wget https://arthas.gitee.io/arthas‐boot.jar
- 运行
用java -jar运行即可,可以识别机器上所有Java进程(我们这里之前已经运行了一个Arthas测试程序,代码见下方)
测试
- 实例代码
package com.jvm.jvm1;
import java.util.HashSet;
public class DeadLockTest {
private static Object lock1 = new Object();
private static Object lock2 = new Object();
public static void main(String[] args) {
hishCPU();
deadLock();
addHashSetThread();
}
private static void addHashSetThread() {
new Thread(()->{
int count=0;
HashSet<Object> set=new HashSet<>();
while (true){
set.add("count"+count);
count++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private static void hishCPU() {
new Thread(()->{
while (true){
}
}).start();
}
private static void deadLock() {
new Thread(()->{
synchronized (lock1){
try {
System.out.println("Abegin");
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2){
System.out.println("Aend");
}
}
}).start();
new Thread(()->{
synchronized (lock2){
try {
System.out.println("Bbegin");
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1){
System.out.println("Bend");
}
}
}).start();
}
}
- 选择进程序号1,进入进程信息操作
- 输入dashboard 查看整个进程的运行情况,线程,内存,GC,运行环境信息;
- 输入thread可以查看线程详细情况
- 输入 thread加上线程ID 可以查看线程堆栈
- 输入 thread -b 可以查看线程死锁
- 输入 jad加类的全名 可以反编译,这样可以方便我们查看线上代码是否是正确的版本
8. 使用 ognl 命令可以查看线上系统变量的值,甚至可以修改变量的值
更多命令使用可以用help命令查看,或查看文档:https://alibaba.github.io/arthas/commands.html#arthas
除了该工具、还有其他的一些、例如jvisualvm,JProfiler等;
GC日志详解
对于java应用我们可以通过一些配置把程序运行过程中的gc日志全部打印出来,然后分析gc日志得到关键性指标,分析 GC原因,调优JVM参数。
‐Xloggc:./gc‐%t.log ‐XX:+PrintGCDetails ‐XX:+PrintGCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M
Tomcat则直接加在JAVA_OPTS变量里。
分析GC日志
运行程序加上对应gc日志
java ‐jar ‐Xloggc:./gc‐%t.log ‐XX:+PrintGCDetails ‐XX:+PrintGCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause
‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M microservice‐eureka‐server.jar
下图中是我截取的JVM刚启动的一部分GC日志
第一行红框为项目的配置参数。。这里不仅配置了打印GC日志,还有相关的VM内存参数。
第二行红框中的是在这个GC时间点发生GC之后相关GC情况。
- 对于2.909: 这是从jvm启动开始计算到这次GC经过的时间,前面还有具体的发生时间日期
- Full GC(Metadata GC Threshold)指这是一次full gc,括号里是gc的原因, PSYoungGen是年轻代的GC, ParOldGen是老年代的GC,Metaspace是元空间的GC
- 6160K->0K(141824K),这三个数字分别对应GC之前占用年轻代的大小,GC之后年轻代占用,以及整个年轻代的大 小
- 112K->6056K(95744K),这三个数字分别对应GC之前占用老年代的大小,GC之后老年代占用,以及整个老年代的 大小
- 6272K->6056K(237568K),这三个数字分别对应GC之前占用堆内存的大小,GC之后堆内存占用,以及整个堆内存 的大小。
- 20516K->20516K(1069056K),这三个数字分别对应GC之前占用元空间内存的大小,GC之后元空间内存占用,以 及整个元空间内存的大小
- 0.0209707是该时间点GC总耗费时间
截图中、发现好几次Full GC都是由于元空间不够导致的,应该将元空间调大点;
java ‐jar ‐Xloggc:./gc‐adjust‐%t.log ‐XX:MetaspaceSize=10M ‐XX:MaxMetaspaceSize=10M ‐XX:+PrintGCDetails ‐XX:+Print GCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M microservice‐eureka‐server.jar
调整完我们再看下gc日志发现已经没有因为元空间不够导致的fullgc了
对于CMS和G1收集器的日志会有一点不一样,也可以试着打印下对应的gc日志分析下,可以发现gc日志里面的gc步骤跟之前的类似;
package com.jvm.jvm1;
import java.util.ArrayList;
import java.util.List;
public class HeapSize {
byte[] a = new byte[1024 * 100];
public static void main(String[] args) throws InterruptedException {
List<Object> list=new ArrayList<>();
while (true){
list.add(new HeapSize());
Thread.sleep(10);
}
}
}
CMS
‐Xloggc:d:/gc‐cms‐%t.log ‐Xms50M ‐Xmx50M ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:+PrintGCDetails ‐XX:+P rintGCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M ‐XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC
G1
‐Xloggc:d:/gc‐g1‐%t.log ‐Xms50M ‐Xmx50M ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:+PrintGCDetails ‐XX:+Pr intGCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M ‐XX:+UseG1GC
上面的这些参数,能够帮我们查看分析GC的垃圾收集情况。但是如果GC日志很多很多,成千上万行。就算你一目十行, 看完了,脑子也是一片空白。所以我们可以借助一些功能来帮助我们分析,这里推荐一个gceasy(https://gceasy.io),可以 上传gc文件,然后他会利用可视化的界面来展现GC情况。具体下图所示
上图我们可以看到年轻代,老年代,以及永久代的内存分配,和最大使用情况。
上图我们可以看到堆内存在GC之前和之后的变化,以及其他信息。 这个工具还提供基于机器学习的JVM智能优化建议,当然现在这个功能需要付费
JVM参数汇总查看命令
java -XX:PrintFlagsInitial 打印所有参数选项的默认值
java -XX:PrintFlagsFinal 打印所有参数选项运行时生效的值