为了账号安全,请及时绑定邮箱和手机立即绑定

深入理解JVM虚拟机12:JVM性能管理神器VisualVM介绍与实战

标签:
Java


# 一、VisualVM是什么?


    VisualVM是一款免费的JAVA虚拟机图形化监控分析工具。


    1\.  拥有图形化的监控界面。

    2\. 提供本地、远程的JVM监控分析功能。

    3\. 是一款免费的JAVA工具。

    4. VisualVM拥有丰富的插件支持。


# 二、如何获取VisualVM?


    VisualVM官方网站:[http://visualvm.java.net/](http://visualvm.java.net/)


    VisualVM各版本下载页面: [http://visualvm.java.net/releases.html](http://visualvm.java.net/releases.html)


     下载VisualVM时也应该注意,不同的JDK版本对应不同版本的VisualVM,具体根据安装的JDK版本来下载第一的VisualVM。



# 三、获取那个版本?


       下载版本参考:[](http://blog.csdn.net/chwshuang/article/details/44200905)[Java虚拟机性能管理神器 - VisualVM(4) - JDK版本与VisualVM版本对应关系](http://blog.csdn.net/chwshuang/article/details/44200905)


备注:下列表中显示1.3.6版本只适合JDK7和JDK8,可是我用1.3.6版还是可以监控JDK1.6_45的版本。 


# 四、VisualVM能做什么?



## 1\. 显示JAVA应用程序配置和运行时环境。


显示JAVA应用程序JVM参数,系统属性,JVM的信息和运行环境。


![](https://img-blog.csdn.net/20150311144957997?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 



## 2\. 显示本地和远程JAVA应用程序运行状态。


可以连接到远程服务器上运行的JAVA应用程序,监控应用程序的运行状态。


![](https://img-blog.csdn.net/20150311151037949?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


## 3\. 监控应用程序的性能消耗。


可以监控到应用程序热点方法的执行单次时间、总耗时、耗时占比。


![](https://img-blog.csdn.net/20150311151314511?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


  


## 4\. 显示应用程序内存分配,显示分析堆信息。


显示应用程序在运行时的编译时间、加载时间、垃圾回收时间、内存区域的回收状态等。


![](https://img-blog.csdn.net/20150311151311969?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


  


## 5\. 监控应用程序线程状态和生命周期。


监控应用程序线程的运行、休眠、等待、锁定状态。


![](https://img-blog.csdn.net/20150311151418254?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


  


## 6\. 显示、分析线程堆信息。


显示线程当前运行状态和关联类信息。


![](https://img-blog.csdn.net/20150311151945542?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


  


## 7\. 支持第三方插件来分析JAVA应用程序。


另外还提供更多更强大、方便的第三方插件。


![](https://img-blog.csdn.net/20150311152144351?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 




  


Java虚拟机性能管理神器 - VisualVM(2)  监控远程主机上的JAVA应用程序


    使用VisualVM监控远程主机上JAVA应用程序时,需要开启远程主机上的远程监控访问,或者在远程JAVA应用程序启动时,开启远程监控选项,两种方法,选择其中一种就可以开启远程监控功能,配置完成后就可以在本地对远程主机上的JAVA应用程序进行监控。


# 1.远程服务器、应用程序配置


##         1.1配合jstatd工具提供监控数据  


###         1.1.1创建安全访问文件


        在JAVA_HOME/bin目录中,创建名称为jstatdAllPolicy文件(这个文件名称也可以顺便起,不过要与jstatd启动时指定名称相同),将以下内容拷贝到文件中。并保证文件的权限和用户都正确。


        grant codebase"file:${java.home}/../lib/tools.jar"{ permission java.security.AllPermission; }; 


  


### 1.1.2启动jstatd服务


        在JAVA_HOME/bin目录中,执行以下命令:


        ./jstatd -J-Djava.security.policy=jstatdAllPolicy-p 1099 -J-Djava.rmi.server.hostname=192.168.xxx.xxx 


  


        jstatd命令描述以及参数说明:


           jstatd是一个基于RMI(Remove Method Invocation)的服务程序,它用于监控基于HotSpot的JVM中资源的创建及销毁,并且提供了一个远程接口允许远程的监控工具连接到本地的JVM执行命令。




        -J-Djava.security.policy=jstatdAllPolicy 指定安全策略文件名称


         -p 1099  指定启动端口


         -J-Djava.rmi.server.hostname=192.168.xxx.xxx  指定本机IP地址,在hosts文件配置不正常时使用,最好加上。


## 1.2JVM启动时配置远程监控选项


        在需要远程监控的JVM启动时,开启远程监控选项


        -Dcom.sun.management.jmxremote.port=1099

        -Dcom.sun.management.jmxremote.ssl=false

        -Dcom.sun.management.jmxremote.authenticate=false

        -Djava.rmi.server.hostname=192.168.xxx.xxx 


  


# 2.本地VisualVM配置


        在本地VisualVM的应用程序窗口,右键单击【远程】》【添加远程主机】》【主机名】中输入远程主机的IP地址,点击【高级设置】输入远程主机开启的监控端口,点击【确定】完成配置。


![](https://img-blog.csdn.net/20150311192951256?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


        如果一切正常,就可以看到远程主机上的JAVA应用程序了。


![](https://img-blog.csdn.net/20150311193119036?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 




  


Java虚拟机性能管理神器 - VisualVM(3)  排查JAVA应用程序内存泄漏


# 1\. 发现问题


    线上应用部署完成后,运行1~2天左右就会出现假死,或者某天早上8~10点高峰期间突然不处理数据了。由于在测试环境的压力测试没有做完全,也没有遇到相关问题。情况出现后对客户的使用造成很大影响,领导要求赶紧排查出问题原因!


# 2\. 排查原因


        排查原因前,与运维沟通,了解线上服务器的运行状态,通过ganglila观察网络、CPU、内存、磁盘的运行历史状态,发现程序故障前,都有一波很高的负载,排查线上日志,负载来源在8~9点平台接入数据量成倍增加,通过与产品和市场人员分析,此时段是用户集中上班、接入平台的高峰时段,访问日志也显示,业务场景正常,无网络攻击和安全问题。属于产品业务正常的场景。


        排除了网络安全因素后,就从程序的运行内部进行排查,首先想到的获取JVM的dmp文件。获取JVM的dmp文件有两中方式:


        1\. JVM启动时增加两个参数,出现 OOME 时生成堆 dump: 


                -XX:+HeapDumpOnOutOfMemoryError


                生成堆文件地址:


                -XX:HeapDumpPath=/home/test/jvmlogs/ 


        2\. 发现程序异常前通过执行指令,直接生成当前JVM的dmp文件,15434是指JVM的进程号


                jmap -dump:format=b,file=serviceDump.dat    15434  


        由于第一种方式是一种事后方式,需要等待当前JVM出现问题后才能生成dmp文件,实时性不高,第二种方式在执行时,JVM是暂停服务的,所以对线上的运行会产生影响。所以建议第一种方式。


# 3\. 解决方案


        获取到dmp文件后,就开始进行分析。将服务器上的dmp文件拷贝到本地,然后启动本地的VisualVM,点击菜单栏【文件】选项,装入dmp文件


![](https://img-blog.csdn.net/20150325170531981?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


        打开dmp文件后,查看类标签,就能看到占用内存的一个排行。


![](https://img-blog.csdn.net/20150325170715642?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


        然后通过检查中查找最大的对象,排查到具体线程和对象。


![](https://img-blog.csdn.net/20150325181223629?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


  


        上列中的com.ctfo.trackservice.handler.TrackHandleThread#4就是重点排查对象。


        通过代码的比对,在此线程中,有调用DAO接口,负责将数据存储到数据库中。而存储到数据库中时,由于存储速度较慢,导致此线程中的数据队列满了,数据积压,无法回收导致了队列锁定,结果就是程序假死,不处理数据。


  


        通过进一步分析,发现数据库存储时有瓶颈,虽然当前是批量提交,速度也不快。平均8000/秒的存储速度。而数据库有一个DG(备份)节点,采用的是同步备份方式,即主库事务要等DG的事务也完成后才能返回成功,这样就会因为网络因素、DG性能因素等原因导致性能下降。通过与DBA、产品、沟通,将同步备份改为异步备份,实时同步改为异步(异步可能会导致主备有10分钟以内的数据延迟)。速度达到30000/秒。问题解决。


        至此,通过VisualVM分析java程序内存泄漏到此结束。不过还有几个问题:1\. 如果dmp文件较大,VisualVM分析时间可能很久;另外,VisualVM对堆的分析显示功能还不算全面。如果需要更全面的显示,就可以使用另外一个专业的dmp文件分析工具【Memory Analyzer (MAT)】,此工具可以作为eclipse的插件进行安装,也可以单独下载使用。如果有感兴趣的朋友,我个人建议还是单独下载使用。下载地址:[http://www.eclipse.org/mat/](http://www.eclipse.org/mat/)   


 


Java虚拟机性能管理神器 - VisualVM(4) 查找JAVA应用程序耗时的方法函数


# 1.为什么要监控?


        JAVA程序在开发前,根据设计文档的性能需求,是要对程序的性能指标进行测试的。比如接口每秒响应次数要求1000次/秒,就需要平均每次请求处理的时间在1ms以内,如果需要满足这个指标,就需要在开发阶段对接口执行函数进行监控,也可以通过打印日志进行监控,从而统计对应的性能指标,然后可以根据性能指标的要求进行相应优化。


# 2\. 那些方法函数需要监控?


        根据具体业务的场景和需求,主要集中在IO通讯、文件读写、数据库操作、业务逻辑处理上,这些都是制约性能的重要因素,所以需要重点关注。


         


# 3\. 如何排查


        在研发环境,大部分会使用syso的方式或者日志方式打印性能损耗,如果代码没有加在运行时才想起来,或者想关注突然想起的函数,换做以前,是需要重启服务的,如果有VisualVM就可以直接查看耗时以及调用次数等情况。而不用打印、输出日志来查看性能损耗。 


![](https://img-blog.csdn.net/20150407164138613?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


# 4\. 如何处理


        对于性能损耗的函数,根据业务逻辑可以进行相应的优化,例如字符串处理、文件读写方式、SQL语句优化、多线程处理等等方式。 


  


       由于性能优化涉及的内容很多,这里就不深入了。主要是告诉大家通过VisualVM来排查问题的具体位置。


  


Java虚拟机性能管理神器 - VisualVM(5) 排查JAVA应用程序线程锁


# 1\. JAVA应用程序线程锁原因


        JAVA线程锁的例子和原因网上一大堆,我也不在这里深入说明,这里主要是否讲如何使用VisualVM进行排查。至于例子可以看这里:[http://blog.csdn.net/fengzhe0411/article/details/6953370](http://blog.csdn.net/fengzhe0411/article/details/6953370) 


这个例子比较极端,一般情况下,出现锁竞争激烈是比较常见的。


# 2\. 排查JAVA应用程序线程锁


       启动 VisualVM,在应用程序窗口,选择对应的JAVA应用,在详情窗口》线程标签(勾选线程可视化),查看线程生命周期状态,主要留意线程生命周期中红色部分。


![](https://img-blog.csdn.net/20150407172335643?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)


(1)绿色:代表运行状态。一般属于正常情况。如果是多线程环境,生产者消费者模式下,消费者一直处于运行状态,说明消费者处理性能低,跟不上生产者的节奏,需要优化对应的代码,如果不处理,就可能导致消费者队列阻塞的现象。对应线程的【RUNNABLE】状态。


(2)蓝色:代表线程休眠。线程中调用Thread.sleep()函数的线程状态时,就是蓝色。对应线程的【TIMED_WAITING】状态。


(3)黄色:代表线程等待。调用线程的wait()函数就会出现黄色状态。对应线程的【WAITING】状态。


(4)红色:代码线程锁定。对应线程的【BLOCKED】状态。


![](https://img-blog.csdn.net/20150407173403625?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h3c2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 


# 3\. 分析解决JAVA应用程序线程锁


        发生线程锁的原因有很多,我所遇到比较多的情况是多线程同时访问同一资源,且此资源使用synchronized关键字,导致一个线程要等另外一个线程使用完资源后才能运行。例如再没有连接池的情况下,同时访问数据库接口。这种情况会导致性能的极具下降,解决的方案是增加连接池,或者修改访问方式。或者将资源粒度细化,类似ConCurrentHashMap中的处理方式,将资源分为多个更小粒度的资源,在更小粒度资源上来处理锁,就可以解决资源竞争激烈的问题。]


  




点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
124
获赞与收藏
549

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消