当咱们系统遇到JVM或者内存溢出等问题的时候,如何对咱们的程序进行有效的监控和排查,就发现了几个比较经常使用的工具,好比JDK自带的 jconsole、jvisualvm
还有一个最好用的工具——jprofiler
,可是这个是收费的,或者除了颇有钱的公司,通常不多人会用这个,还有一个就是咱们今天的主角——Arthas ,为何今天会重点讲这个呢?html
官网地址:arthas.gitee.io/ GitHub地址:github.com/alibaba/art…java
Arthas 是Alibaba开源的Java诊断工具,采用命令行交互模式,提供了较为丰富的功能,主要仍是他是免费里面的算是好用且功能比较强大的一个JVM排查的插件,在了解这个利器以后,发现仍是挺好用的,并且支持的功能也比较全面,那么Arthas到底能够为咱们作哪些事情呢?git
之前,你碰到这些问题,解决的办法大可能是,修改代码,从新上线。可是在大公司里,上线的流程是很是繁琐的,若是为了多加一行日志而从新发布版本,无疑是很是折腾人的。可是阿里巴巴开源的Arthas 有了更为优雅的线上调试方法。github
Arthas 支持JDK6,同时能够在 Linux/Mac/Windows
上运行,自动Tab 补全功能,更方便咱们定位问题和诊断web
下载地址:arthas.gitee.io/download.ht… 你能够下载zip的包我下载的是arthas-packaging-3.5.0-bin.zip 或者经过命令去下载正则表达式
wget https://alibaba.github.io/arthas/arthas-boot.jar
算法
当咱们下载好以后,咱们直接经过命令启动就能够java -jar arthas-boot.jar
,可是在此以前咱们须要经过检测的代码来挂靠到Arthas上面apache
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class FullGCTest {
//模拟银行卡的类
private static class CardInfo {
//小农的银行卡信息记录
BigDecimal price = new BigDecimal(10000000.0);
String name = "牧小农";
int age = 18;
Date birthdate = new Date();
public void m() {}
}
//线程池 定时线程池
//50个,而后设置 拒绝策略
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardOldestPolicy());
public static void main(String[] args) throws Exception {
executor.setMaximumPoolSize(50);
for (;;){
modelFit();
Thread.sleep(100);
}
}
/** * 对银行卡进行风险评估 */
private static void modelFit(){
List<CardInfo> taskList = getAllCardInfo();
//拿出每个信息出来
taskList.forEach(info -> {
// do something
executor.scheduleWithFixedDelay(() -> {
//调用M方法
info.m();
}, 2, 3, TimeUnit.SECONDS);
});
}
private static List<CardInfo> getAllCardInfo(){
List<CardInfo> taskList = new ArrayList<>();
//每次查询100张卡出来
for (int i = 0; i < 100; i++) {
CardInfo ci = new CardInfo();
taskList.add(ci);
}
return taskList;
}
}
复制代码
这个是上篇文章讲述的案例,感兴趣的能够了解一下。centos
首先咱们须要使用javac 命令将Java文件进行编译javac FullGCTest.java进行编译,而后打印GC日志,进行风险监控打印GC日志: java -Xms200M -Xmx200M -XX:+PrintGC FullGCTest
服务器
Arthas启动命令:java -jar arthas-boot.jar
咱们就看到了咱们刚才启动的FullGCTest的应用程序,咱们输入编号 1 回车,这样咱们就把Arthas挂靠到咱们的程序上,接下来咱们只须要作对应的命令操做就能够了
命令详情文档:arthas.aliyun.com/doc/command…
命令 | 详细说明 |
---|---|
jvm | 查看当前JVM信息 |
thread | 查看当前JVM的线程堆栈信息 |
watch | 方法执行数据观测 |
dashboard | 当前系统的实时数据面板 |
trace | 方法内部调用路径,并输出方法路径上的每一个节点上耗时 |
stack | 输出当前方法被调用的调用路径 |
tt | 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不一样的时间下调用进行观测 |
vmoption | 查看,更新JVM已加载的类信息 |
sc | 查看JVM已加载的类信息 |
sm | 查看已加载类的方法信息 |
jad | 反编译指定已加载类的源码 |
classloader | 查看classloader的继承树,urls,类加载信息 |
heapdump | 相似jmap命令的heap dump 功能 |
OPERATING-SYSTEM:系统相关参数
THREAD相关:
MEMORY
FILE-DESCRIPTOR(文件描述符相关):
参数说明:
命令 | 详细说明 |
---|---|
id | 线程id |
[n:] | 指定最忙的前N个线程并打印堆栈 |
[b] | 找出当前阻塞其余线程的线程 |
[i] | 指定cpu使用率统计的采样间隔,单位为毫秒,默认值为200 |
[--all] | 显示全部匹配的线程 |
打印当前最忙的N个线程并打印堆栈 thread -n 3
thread 查看全部线程
thread 17: 显示指定线程的运行堆栈
thread -i: 指定采样时间间隔
thread -i 1000 : 统计最近1000ms内的线程CPU时间。 thread -n 3 -i 1000 : 列出1000ms内最忙的3个线程栈
运行程序时,会显示当前程序的实时信息,如qps, rt, 错误数, 线程池信息等等
数听说明:
参数说明:
参数名称 | 详细说明 |
---|---|
id | 刷新实时数据的时间间隔 (ms),默认5000ms |
[n:] | 刷新实时数据的次数 |
查看JVM已加载的类信息,经过SC咱们能够看到咱们这个类的详细信息,包括是从哪一个jar包读取的,他是否是接口/枚举类等,甚至包括他是从哪一个类加载器加载的。
参数说明:
参数名称 | 详细说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
[d] | 输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。若是一个类被多个ClassLoader所加载,则会出现屡次 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
sc -d *CardInfo
: 打印类的详细信息
sc -d -f *CardInfo
:打印类的Fiedld信息
heapdump:相似于jmap命令
建立到指定文件夹下:
[arthas@365564]$ heapdump /usr/local/mxn/dump.hprof
Dumping heap to /usr/local/mxn/dump.hprof ...
Heap dump file created
复制代码
建立成功后,咱们就能够在指定文件夹下看到对应的dump文件,而后使用命令jhat dump.hprof
,生成文件,成功后咱们就能够经过IP+端口进行访问了
访问:
而后咱们就能够经过IP+端口去访问它了,里面有个他的other,咱们拉到最底下,找 Show instance counts for all classes (including platform)
从下面咱们能够分析出来哪一个类包含的对象最多,分析出来哪一个类产生的对象
这个里面最强大的功能仍是叫作 Execute Object Query Language (OQL) query
,这个里面能够显示有哪些对象,对象有多少个字节和引用,能够观察到哪一个对象产生了问题,以下图所示,显示全部String对应的对象
搜索点进去以后咱们还能看到这个对象到底占用了多少个字节,有多少个引用指向了这个Object,这个OQL的语法也是很灵活,咱们可使用where条件去过滤
jad:反编译某个类,或者反编译某个类的某个方法,动态代理生成类的问题定位 第三方的类(观察代码) 版本问题(肯定本身最新提交的版本是否是被使用)
有人可能会问这个有啥用,源码我不是本身就知道吗?由于有时咱们常常会不肯定线上或者测试环境的包是不是咱们修改过的,这时候就能够经过jad反编译来看下,是不是最新的代码
redafine:热替换,动态更新代码,不用重启jvm目前有些限制条件:只能改方法实现(方法已经运行完成),不能改方法名, 不能改属性 m() -> mm()
好比咱们在线上环境有个class确认有问题,想要从新替换,通常状况下只能停掉服务器从新发布,在普通的小公司这样是能够的,可是在大规模公司京东淘宝这样的是不能停的,由于整个流程是很是复杂的,那怎么办呢?你们能够看到下面的案例
首先咱们新建一个测试案例:
public class T{
public static void main(String[] args) throws Exception{
for(;;){
System.in.read();
new TT().m();
}
}
}
复制代码
public class TT{
public void m(){
System.out.println(2);
}
}
复制代码
使用命令javac *.java
,编译成class文件,而后运行 T 文件
[root@VM-0-7-centos t]# java T
a
2
2
复制代码
当咱们输入a的时候打印2,可是咱们上线之后才发现,咱们须要输出的1,这个是若是要从本地更改要从新发布上线,为了这一个修改,明显是不值当的,可是若是咱们用 redafine 热部署就能够帮助咱们直接替换,不用从新发布jvm
而后咱们将 T 这个程序挂靠到 Arthas 上面去
而后咱们直接修改 TT.java 程序 vi TT.java
,将里面打印2的值修改为1
public class TT{
public void m(){
System.out.println(1);
}
}
复制代码
而后编译执行 ```javac TT.java ````
在回到咱们挂靠的Arthas 上面执行 redefine /usr/local/mxn/fuccGc/t/TT.class
[arthas@398842]$ redefine /usr/local/mxn/fuccGc/t/TT.class
redefine success, size: 1, classes:
TT
复制代码
执行成功 你们能够看到咱们在没有从新启动的状况下成功替换了class文件
watch:方法执行的数据观测,能够经过watch指令,来监控某个类,监控后,运行下你的功能,复现下场景,arthas会提供给你具体的出参和入参,帮助你排查故障
输出方法调用路径,并输出耗时,这个指令对于优化代码很是的有用,能够看出具体每一个方法执行的时间,若是是for循环等重复语句,还能看出n次循环中的最大耗时,最小耗时,和平均耗时,完美!
在咱们对某个方法开启tt后,会记录每一次调用(咱们能够设置最大监控次数)的入参和返回参数,并能对这些不一样时间下调进行观测
[arthas@405136]$ tt -t FullGCTest modelFit
命令参数解析-t tt 命令有不少个主参数,-t 就是其中之一。这个参数的代表但愿记录下类 *Test 的 print 方法的每次执行状况。 -n 3 当你执行一个调用量不高的方法时可能你还能有足够的时间用 CTRL+C 中断 tt 命令记录的过程,但若是遇到调用量很是大的方法,瞬间就能将你的 JVM 内存撑爆。
此时你能够经过 -n 参数指定你须要记录的次数,当达到记录次数时 Arthas 会主动中断tt命令的记录过程,避免人工操做没法中止的状况。
ognl表达式
OGNL特殊用法请参考:github.com/alibaba/art… OGNL表达式官方指南:commons.apache.org/proper/comm…
调用静态函数:ognl '@java.lang.System@out.println("hello")'
获取静态类的静态字段:ognl '@FullGCTest@random'
Arthas还支持Web Console,详见:alibaba.github.io/arthas/web-…
Arthas是一个线上Debug神器,相比于其余工具,Arthas有着比较全面的功能,上手也比较容易,对于刚开始入门的小伙伴也是能够轻松掌握的,对于文中有不懂或者有问题的小伙伴,你们能够在下面留言评论。
原创不易,但愿你们多多捧场,记得一键三连!!!
我是牧小农,怕什么真理无穷,进一步有进一步的欢喜,你们加油!