欢迎来到思维库

思维库

强大的JVM监控工具!

时间:2025-11-05 12:43:27 出处:焦点阅读(143)

介绍

在生产环境中,监控经常会遇到各种各样奇葩的工具性能问题,所以掌握最基本的监控JVM命令行监控工具还是很有必要的

名称 主要作用 jps 查看正在运行的Java进程 jstack 打印线程快照 jmap 导出堆内存映像文件 jstat 查看jvm统计信息 jinfo 实时查看和修改jvm配置参数 jhat 用于分析heapdump文件

jps:查看正在运行的Java进程

jps可以列出正在运行的Java进程,并显示虚拟机执行主类(Main Class,工具main()函数所在的监控类)名称以及进程id

「如果想看一个命令的后面加 -help参数即可」

[root@VM-0-14-centos ~]# jps -help usage: jps [-help]        jps [-q] [-mlvV] [<hostid>] Definitions:     <hostid>:      <hostname>[:<port>] 

「可以看到可以监控远程服务,但是工具基于安全考虑,一般不使用」

常见的监控选项如下

选项 作用 -q 只输出进程id -m 输出传递给主类main函数的参数 -l 输出主类全类名,如果进程执行的工具是Jar包,输出jar包名字 -v 程序启动时指定的监控jvm参数 cis@mt002:~$ jps 70208 KmpService 183525 LinkAnalysisServer 25160 MipSerachServer  cis@mt002:~$ jps -l 70208 com.st.kmp.main.KmpService 183525 com.st.cis.main.LinkAnalysisServer 25160 com.st.cis.main.MipSerachServer 

jstack:打印线程快照

「查看某个Java进程中所有线程的状态。一般用来定位线程出现长时间停顿的工具原因,如发生死循环,监控死锁,工具请求外部资源长时间等待等!」

public class DeadLockDemo {     private static Object lockA = new Object();     private static Object lockB = new Object();     public static void main(String[] args) {         Thread threadA = new Thread(() -> {             synchronized (lockA) {                 try {                     TimeUnit.SECONDS.sleep(1);                 } catch (InterruptedException e) {                     e.printStackTrace();                 }                 System.out.println("get lockA");                 synchronized (lockB) {                     System.out.println("threadA run finish");                 }             }         });         Thread threadB = new Thread(() -> {             synchronized (lockB) {                 try {                     TimeUnit.SECONDS.sleep(1);                 } catch (InterruptedException e) {                     e.printStackTrace();                 }                 System.out.println("get lockB");                 synchronized (lockA) {                     System.out.println("threadB run finish");                 }             }         });         threadA.setName("myThreadA");         threadB.setName("myThreadB");         threadA.start();         threadB.start();     } } 

「我写了一个死锁的监控例子,源码库启动后执行jps找到进程id为19457」

peng@pengdeMacBook-Pro ~ % jps 19457 DeadLockDemo 19458 Launcher 2658  19459 Jps 

接着执行如下命令,工具列出了这个进程每个线程的监控执行状态

jstack 19457 

「从图中可以看到有很多线程,GC线程,myThreadA,myThreadB等,其中myThreadA和myThreadB的线程状态为BLOCKED,并且在最后提示出了死锁发生的位置」

jmap:导出堆内存映像文件

「jmap主要用来用来导出堆内存映像文件,看是否发生内存泄露等。」

生产环境我们一般会配置如下参数,让虚拟机在OOM异常出现之后自动生成dump文件

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/peng 

执行如下命令即可手动获得dump文件

jmap -dump:file=文件名.dump 进程id 

「分析堆内存的工具有很多,如Java VisualVM,jhat等。但个人觉得最好用的就是Eclipse Memory Analyzer,没有之一」

jstat:查看jvm统计信息

「jstat可以显示本地或者远程虚拟机进程中的类装载、 内存、 垃圾收集、 JIT编译等运行数据」

用jstat查看一下类装载的信息。我个人很少使用这个命令,命令行看垃圾收集信息真不如看图形界面方便,就不多做介绍了。

[root@VM-0-14-centos ~]# jstat -class 19402 Loaded  Bytes  Unloaded  Bytes     Time     10229 19679.1       52    76.0       5.33 

含义如下

Loaded 解释 Loaded 加载类的企商汇个数 Bytes 加载类的字节数 Unloaded 卸载类的个数 Bytes 卸载类的字节数 Time 花费的时间

jinfo:实时查看和修改jvm配置参数

jinfo的作用是实时地查看和修改虚拟机各项参数。

「使用jps命令的-v参数可以查看虚拟机启动时显式指定的参数列表」,但如果想知道未被显式指定的参数的系统默认值,除了去找资料外,就只能使用jinfo的-flag选项进行查询了(如果只限于JDK 1.6或以上版本的话,使用java -XX:+PrintFlagsFinal查看参数默认值也是一个很好的选择)

「jinfo flags pid在高版本才能正常使用,我在jdk1.8这个版本不能正常使用」

应用程序设置如下参数

-Xmx10m -Xms10m 

查看最大堆内存和是否打印GC日志,可以看到不打印GC日志 接着设置打印GC日志,再次查看,打印GC日志

peng@pengdeMacBook-Pro ~ % jinfo -flag MaxHeapSize 20253          -XX:MaxHeapSize=10485760 peng@pengdeMacBook-Pro ~ % jinfo -flag PrintGCDetails 20253 -XX:-PrintGCDetails peng@pengdeMacBook-Pro ~ % jinfo -flag +PrintGCDetails 20253 peng@pengdeMacBook-Pro ~ % jinfo -flag PrintGCDetails 20253  -XX:+PrintGCDetails 

「Xmx是MaxHeapSize的别名」

本文转载自微信公众号「Java识堂」,可以通过以下二维码关注。转载本文请联系Java识堂公众号。

香港云服务器

分享到:

上一篇:电脑开机时显示脚本错误的解决方法(识别和修复电脑开机时显示脚本错误的常见问题)

下一篇:因为把Ubuntu从13.04升级到13.10后,鼠标出现了问题,一打开网页就不停的闪,而且好多东西都不一样了,又不好用,所以选择重装系统,重装的时候偏偏又重新分了区,然后装完了,一重启,悲剧了,进入修复grub rescue模式下了,一时间就不知道怎么办好了,好在还有个平板可以上网,马上上网搜。很快就搜到不少,点开第一个,“用U盘启动进入Windows系统重写mbr”?那我的Ubuntu不就没了!!!直接PASS!!!“直接在grub rescue”下修复,嗯,这个好。马上按给的方法试,我去,完全不一样好不好!完全没有变化!!再接着搜,嗯,这篇好像靠谱多了,还写了出现这种问题对应的情况,不错,有重新分区造成的,这个看起来是了。马上照着做。1、输入set查看当前的设置(原来这个是查看当前设置的,先前搜到的都不说清楚)2、输入set root=(hd0,msdos11),难怪刚才我的没有变化,选择前搜到的根本没有set,直接就root=(hd0,msdos11)了。(msdos11是我Ubuntu安装的位置,每个人不同的,可以用ls (hd0,x)/root/grub 查看安装到哪个分区了,运行命令后出现很多文件的就是了)3、输入insmod /grub/normal.mod,我靠,没有这个文件,什么情况!!!难道我的不是Ubuntu!!这不科学!!!冷静,要冷静!检查Ubuntu安装在哪个盘时还有几个文件夹,会不会是文件的路径不一样,嗯,查看一个其它文件路径看看,输入ls (hd0,msdos11)/root/grub/i386-pc,一个回国,出来一大串的文件名,大部分是.mod和.img的,应该就是这个了,把命令换成insmod (hd0,msdos11)/root/grub/i386-pc/normal.mod,成功!!!!4、输入normal,回车的,熟悉的启动菜单出来了。不过还没有完。5,进行Ubuntu,打开终端,输入sudo update-grub,更新一下引导文件。6、输入sudo grub-install /dev/sda,等待几秒,我靠,失败,还没有原因!!算了,重启试试。等待中。。。我去,又是grub rescue!!!重新来过,再次进入Ubuntu,把网页再往下拉,还有解决的方法,不过刚才因为是要用live cd启动就没管,再试这个方法好了!(一般情况到这里应该就修复完成了,不过我的情况不一样,我是在重装时又重新分了区,而且还重新指定了引导文件存在的位置导致的,需要再用到下面的方法才行。)7、输入sudo mount /dev/sda11 /mnt,把安装的盘挂载到/mnt上8、输入sudo grub-install --boot-directory=/mnt/boot/dev/sda,我靠,出来这一串东西是什么,我没输入错误啊,怎么不是运行成功!再试!还是这样!!!!重复试了几次后,算了,重启吧,奇迹般的启动菜单出来了!!原来已经执行成功了吗?!!好了!这就是过程了,我的小心脏啊!!!(这是没有把/boot单独分出来的方法,把/boot单独分出来的话就把命令中的“/boot”去掉就好了)

温馨提示:以上内容和图片整理于网络,仅供参考,希望对您有帮助!如有侵权行为请联系删除!

友情链接: