性能测试之jvisualvm监控分析

发表于:2018-2-01 11:23

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:农佳技    来源:51Testing软件测试网采编

  前言
  现实企业级Java项目中,有时候会碰到下面这些问题:
  ●OutOfMemoryError,内存不足
  ●内存泄露
  ●线程死锁
  ●锁争用(Lock Contention)
  ●Java进程消耗CPU过高
  ●......
  这些问题在日常开发中可能被很多人忽视(比如有的人遇到上面的问题只是重启服务器或者调大内存,而不会深究问题根源),但作为一名优秀的性能测试工程师,必须能够定位并分析这些问题。那么在性能测试的整个流程当中,如何来监控这些问题呢?这里介绍如何使用 JVisualVM 进行性能监控分析。
  jvisualvm 安装
  JDK中还藏着一个宝贝,它的名字叫做VisualVM,自从 JDK 6 Update 7 以后已经作为 Oracle JDK 的一部分,它主要用来监控JVM的运行情况,可以用它来查看和浏览Heap Dump、Thread Dump、内存对象实例情况、GC执行情况、CPU消耗以及类的装载情况。该工具位于 JDK 根目录的 bin 文件夹下,无需安装,正常安装完jdk后,至jdk的bin目录下直接运行jvisualvm.exe即可。
  jvisualvm 插件安装,选择【工具】——【插件】——【可用插件】,打开后如下图,没有检测到可用插件
  然后点击检测最新版本,提示无法连接到java visualvm插件中心,这是因为java.net网站已经被Oracle关闭了,visualvm已经迁移到了github上,地址是https://visualvm.github.io/index.html,点击Plugins进入插件页面
  因为我的jdk是1.7.0_80,所以找到对应插件更新地址https://visualvm.github.io/archive/uc/8u40/updates.xml.gz
  再次回到jvisualvm-》工具-》插件,找到设置
  把红色框中的url地址改成刚才找到的https://visualvm.github.io/archive/uc/8u40/updates.xml.gz,修改之后,更新可用插件,安装即可。重启jvisualvm。
  jvisualvm远程监控
  jvisualvm可以监控所有的java进程,本地机器的程序直接可以监听到,远程机器的程序需要加上JVM参数,下面以监控远程tomcat为例介绍如何添加远程监控。
  1、远程服务器配置
  在tomcat/bin/catalina.sh加入以下配置:
  JAVA_OPTS="-Djava.rmi.server.hostname=10.1.60.63 -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
  端口号可以自己定义,如果冲突了,修改下就好了。配置好后,重启tomcat。那问题又来了,jar包如何配置监听呢?比如我们的前置机。其实很简单,只要启动jar包时加上上面的配置参数就好了。命令如下:nohup java -jar Djava.rmi.server.hostname=192.168.1.24 -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false  /home/webapps/test_front_end_service/front-end-service.jar &
  2、在jvisualvm中进行远程配置
  具体如下:

  到此远程监控添加完成了,在远程主机下会有一个jmx连接,打开连接,点击监视tab,可以看到如下界面了.
  在上图中可以看到cpu利用率和垃圾回收活动,然后是堆栈使用情况(这两个在分析tomcat性能时很重要)。下面是类的使用情况,最后一个是线程活动情况。
  点击线程tab可以看到:下图可以非常清晰的看到线程活动情况,那些线程正在执行,哪些线程正在等待中,以及执行完毕的线程等。这里可以看到每个线程的状态,点击某个线程右键可以查看该线程的详细情况:
  线程死锁检测
  前面已经介绍如何安装插件,jvisualvm推荐16种插件,其中Threads Inspector插件可以轻松地检测到死锁,当压测过程中出现死锁,在线程tab页会出现如下的提示
  从上图可知,检测到死锁,可以通过【线程Dump】查看具体的死锁线程的信息
  Main.Java 21行:Thread-0当前锁定了
  <0x00000000dbb308f0>,并且在等待锁定<0x00000000dbb308c0>
  Main.Java 32行:Thread-1当前锁定了
  <0x00000000dbb308c0> ,并且在等待锁定
  <0x00000000dbb308f0>
  两个进程互相都需要对方线程释放其所占有资源(java.lang.String),而根据【请求与保持条件】原则,显然不会释放已经到手的资源,可以说是吃着碗里的,看着锅里的,两边都想占有。
  内存分析
  jvisualvm 通过检测 JVM 中加载的类和对象信息等帮助分析内存使用情况,可以通过  jvisualvm的监视标签和 抽样器对应用程序进行内存分析。下面以分析内存泄漏为例。
  性能测试过程中,如何去发现内存问题:jvm分配的内存是否够用,是否有大对象占用太多内存,监控时哪样的图形反映内存泄漏的风险?
  如上图中,堆大小和使用的堆大小一目了然。当压力稳定的情况下,出现如上的图形,说明有内存泄漏的风险。从上图可以看到,虽然每次Full GC,JVM内存会有部分回收,但回收并不彻底,不可回收的内存对象会越来越多,这样便会出现以上的一个步步高的趋势。在Full GC无法回收的对象越来越多时,最终已使用内存达到系统分配的内存最大值,系统最后无内存可分配,最终内存溢出,导致down机。Java尽管采用自动的内存管理方式,但是仍然存在泄露的可能,JVM认为对象没有引用时,会把这个对象视为垃圾。Java内存泄露就存在于,这个对象实际上已经不再需要,但是仍然存在引用,此时就会产生内存泄露。
  如何找到导致内存泄漏的程序?打开抽样器标签:点击内存后如下图:
  多次执行gc前后分别堆dump一次,进入最后dump出来的堆标签,点击类:点击右上角:“与另一个堆存储对比”。如图选择第一次导出的dump内容比较:
  比较结果如下:
  dump出来的类中看到有很多是jdk的基础类型,那么分析程序的时候显然只分析和程序员相关的,按实例数或大小排序优先分析,找到我们程序自定义的包名,如上图中com.memory.test。可以看到多次gc后,TestMemory对象实例一直在增加,说明该对象引用的方法可能存在内存泄漏。如何查看对象引用关系呢?双击选择类TestMemory,如下所示:
  左侧是创建的实例总数,右侧上部为该实例的结构,下面为引用说明,从图中可以看出在类CyclicDependencies里面被引用了,并且被HashMap引用。
  如此可以确定泄漏的位置,进而根据实际情况进行分析解决。
  cpu分析
  jvisualvm 能够监控应用程序在一段时间的 CPU 的使用情况,显示 CPU 的使用率、方法的执行效率和频率等相关数据帮助发现应用程序的性能瓶颈。可以通过 jvisualvm的监视标签和 抽样器对应用程序进行 CPU 性能分析。
  在监视标签内,可以查看 CPU 的使用率以及垃圾回收活动对性能的影响。过高的 CPU 使用率可能是由于项目中存在低效的代码,可以通过 抽样器对 CPU抽样进行详细的分析。如果垃圾回收活动过于频繁,占用了较高的 CPU 资源,可能是由内存不足或者是新生代和旧生代分配不合理导致的等。如下图中:
  观察右边的使用堆图形,图形呈锯齿状,说明垃圾不断地被回收,cpu图形中也发现频繁的gc导致cpu不稳定,再通过监控gc情况进一步分析是否内存分配不合理,使用的是什么垃圾回收策,是否有回收不掉的对象。关于gc需要理解java内存模型、垃圾回收机制,这里不再详述。
  项目实例分析
  以近期前置机接口性能测试为例,围绕如何根据性能指标通过监控jvm分析系统性能瓶颈。下面是投标接口压测过程中表现出来的前端指标

  上图中图1为并发用户数,2图为点击率,图3为tps。并发用户数与点击率,与tpsf都是正相关的关系。即当并发用户数不断增加时,点击率也应线性地增加,如果用户数增加点击率增加长缓慢或平稳或下降,都是性能不良好的表现。图中当并发用户加载到40个左右时,点击率都是跟随着性能增涨,用户数再往上增加时,点击率不增涨反而有所下降。说明服务器处理能力遇到瓶颈。这时通过jvisualvm工具监控到cpu不足,jvm内存频繁的回收,如下图
  结合打印gc信息,发现ygc每秒1次
  优化的思路从减少ygc入手,可通过调整gc算法,增大年轻代大小来优化。gc是一个复杂的过程,调整参数后需要经过详细的测试,验证是否达到优化的目的。本人水平也非常有限,讲得不对的地方,还望大家指教一起探讨。
  cpu方面结合top,可发现cpu load过高,如下图:
  再进行cpu抽样,可查看哪些方法占用cpu高,那么优化cpu就可从两方面入手:1、硬件上增加cpu 2、代码上对占用cpu的高方法进行代码分析优化,当然这个得开发人员进行配合分析了。如下图中,打印日志的方法消耗cpu比较高,可把日志级别调低。
  增加cpu后,性能指标得到明显提升,最高tps可达到190。如下图




上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号