深入学习JVM(6): Jvm调优工具-Arthas

一. 前言

今天说的是阿里开源的Jvm调优工具Arthas, 这个工具的强大之处应该都有所耳闻了. 它也不仅仅只是一个调优工具, 有非常多强大的功能. 比如热加载类, 动态更新内存变量等等.

二. Jdk自带的调优命令

说起调优工具, Jdk自带的命令也必不可少, 不过这里只简单的记录一下, 不是本文的重点. 因为真正在观察Jvm运行情况的时候, Arthas要方便的多.

  1. 查看当前有哪些java程序正在运行: jps
    jps

  2. 查看Jvm内存情况命令: jmap
    ① 查看内存占用情况及实例个数: jmap -histo 进程id 可以选择输入到文件(jmap -histo 进程id > test.txt)后再打开查看.
    ② 查看堆信息: jmap -heap 进程id
    ③ 导出dump文件: jmap ‐dump:format=b,file=test.hprof 进程id format: 格式化, file: 输出文件. 可以通过jvisualvm打开, jvisualvm也是jdk自带的工具(图形化的), 如果有配置jdk环境变量的话, 可以在windows的cmd上直接输入jvisualvm打开.
    ④ 除了主动导出dump文件之外, 也可以配置如下Jvm参数导出:
    -XX:+HeapDumpOnOutOfMemoryError
    -XX:HeapDumpPath=./
    配置之后, Jvm会在堆内存溢出时, 导出dump文件, 方便后续排查导致内存溢出的故障

  3. 查看Jvm运行信息: jinfo
    ① 启动参数: jinfo -flag 进程id
    ② 运行环境信息: jinfo -sysprops 进程id

  4. 查看Jvm堆栈信息: jstack
    ① 查找死锁或查看线程运行情况: jstack 进程id
    ② 查看某一个线程的堆栈信息, 此处列出查找占用CPU最高的线程:

1. top -p 进程id           // 列出指定进程的信息

2. 按下 H (大写)           // 列出该进程的所有线程

3. 将CPU占用最高的线程id转为16进制, 因为java的线程id是用16进制来表示的, 
top把它转为了十进制展示. 如: 28071 = 6da7

4. jstack 进程id | grep -A 20 6da7    //可以打印出该线程正在执行的近20行代码
  1. 查看垃圾收集统计: jstat
    jstat -gc 进程id
    这个比较重要, 放个图:
image.png

除了最后一个之外, 其它的没有截图, 请自行尝试. 上述的所有命令都在jdk/bin目录下, 并且都可以通过 -h 查看帮助, 如: jmap -h

三. Arthas工具

千呼万唤始出来, 终于到Arthas了. 前面的命令可以了解一下即可, 重点记住这个工具就行, 我也不会写的太多, 只会列出几个常用的命令, 因为官网的在线教程做的真是天衣无缝~

附上Arthas官网地址: http://arthas.gitee.io/

下面一起来看看常用的功能吧(仅记录, 不做初级使用教程, 入门请看官网.):

  1. 支持了一些基础命令, 如cat, pwd, grep, echo, history等, 了解Linux同学的应该会很清楚这些命令. 对了, 同样支持 “ > ”, 将输出的内容追加到某一个文件中. 还有一个session, 可以查看当前进入的java进程号.

  2. vmoption: 查看Jvm的诊断参数, 默认查看全部.
    (1) 可以通过加上参数名只看某一个, 如: vmoption PrintGCDetails
    (2) 更神奇的是可以通过此参数修改它: vmoption PrintGCDetails true

  3. thread: 查看Jvm中线程的资源占用情况
    (1) 可以通过 -n 参数查看指定个数最忙的线程: thread -n 3, 会直接打印出线程堆栈, 不必再像之前原生的Jvm参数jstack那样找来找去最后还要进行进制转换了. 也可以通过thread -n 3 -i 1000查看1秒中最忙的3个线程
    (2) 而直接使用thread命令, 会打开一个类似top命令一样的界面, 不同的是它展示的是当前java进程的线程占用资源情况.
    (3) thread -b查看死锁情况或锁阻塞情况. 或者通过thread --state WAITING命令查看指定状态的线程, 阻塞的状态是: BLOCKED

  4. 强大的ognl命令. 通过Arthas的ognl命令可以动态执行java代码, 或者修改一些变量的值. 这是一个非常厉害的特性, 应用场景...在下没有想到, 反正当代码发布到正式环境之后, 一切都显得阻碍重重.
    (1) 动态执行代码: ognl '@java.lang.System@out.println("hello ognl")'调用System类的out.println方法. 意思是, 使用类名全路径, 再写上自己的方法名, 就可以调用了.
    (2) 查看静态变量的值:
    ognl -c 类加载器hash @com.example.demo.arthas.user.UserController@logger; 这个命令需要加上类的类加载器hash值, 所以需要先使用sc -d 类路径查找出加载该类的类加载器, 如:
    sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash
    可以加上 -x 参数指定需要展开的层数(当一个静态变量为对象, 且又包含多个对象时使用)
    (3) ognl表达式, 官方例子:
    ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
    通过表达式, 声明value1和value2两个临时变量并赋值, 返回一个List. 更多的我没有去了解, 因为没有用到, 估计学了也忘的快.

  5. 查看Jvm信息: Jvm, 可以查看到堆内存的分配, 以及gc情况(包括gc算法)

  6. dump堆内存信息: heapdump /tmp/dump.hprof

  7. 查看Jvm监控面板: dashboard, 可以看到线程的资源占用情况, 以及堆内存占用情况和GC情况.

  8. 快速查看方法运行是否正常: tt -t -n 10 demo.MathGame primeFactors -n 10 : 打印10次

  9. 查看某个方法的执行所消耗的时间: trace demo.MathGame run -n 10如果需要过滤可以加上表达式: trace demo.MathGame run -n 10 '#cost > 10'; 如果想要观察多个类的多个方法的执行(一般是排查调用链), 可以使用表达式: trace -E com.test.ClassA|org.test.ClassB method1|method2|method3

四. Arthas热更新类

这个用的最多, 单独拎出来写. 热更新一个类有多种做法:

  • 方式一: 直接在本地将类编译好, 上传到服务器上, 然后进入Arthas执行命令:
    redefine /tmp/TestDemo.class即可.
    (1) 不过redefine之后的类是不能复原的, 这意味着...如果你为了改一个bug, 却出现了两个bug...需要再次将本地代码还原, 编译, 上传, 然后再次redefine才行.
    (2) 又不过好在Arthas提供了另一个命令: retransform /tmp/TestDemo.class, retransform热加载的类就能够还原.
    (3) 通过retransform -l可以看到通过retranform命令加载的类列表
    (4) 通过retransform -d id移除指定的热加载进来的类. 此处的id是通过上一条命令查询到的. 也可以通过retransform --deleteAll删除所有热加载进来的类.
    (5) 注意! 执行上方移除后, 热加载的类仍在Jvm内存中, 需要重新执行一次retransform命令: retransform --classPattern com.test.TestDemo, 这样才能还原.
    (6) PS: 我个人还是比较偏向redefine, 本地做好测试即可.
    还有!!! 不论redefine还是retransform, 都不能热更新更改了方法签名或类成员变量的类. 方法签名: 方法的作用域, 返回值, 方法名, 方法参数
  • 方式二: 官网的标准流程, 中间步骤可根据情况省略:
    (1) jad --source-only com.TestDemo > /tmp/TestDemo.java 将要热更新的类反编译至一个java文件中
    (2) 修改该文件中的java代码
    (3) sc -d *UserController | grep classLoaderHash 找到该类的类加载器的hash值, 一般打印如下: classLoaderHash 1be6f5c3
    (4) mc -c 1be6f5c3 /tmp/TestDemo.java -d /tmp 将修改好的java文件编译到指定目录. -c 指定类加载器; -d 指定编译目录
    (5) 使用redefineretransform命令热更新该类

全文结束, 不过还是希望小伙伴儿们去官网在线尝试一下, 绝对受益匪浅. 然后也欢迎指正~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容