好贷网好贷款

通过jstat、jmap对java程序进行性能调优

发布时间:2016-12-4 5:58:00 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"通过jstat、jmap对java程序进行性能调优",主要涉及到通过jstat、jmap对java程序进行性能调优方面的内容,对于通过jstat、jmap对java程序进行性能调优感兴趣的同学可以参考一下。

原文:http://blog.csdn.net/jerry024/article/details/8507589 某大型银行某系统性能调优过程跟踪记录   http://www.csdn123.com/html/blogs/20130615/22487.htm 1. 背景 硬件供应商多次反映,在tomcat启动一段时间后,经常出现cpu占用率100%,且重启前一直保持在100%的情况。在重启后cpu占用率回落,但是一段时间后再次出现问题。 下图为cpu占用率100%时使用top命令的截图,可以看到java进程的cpu占用率几经几乎达到了400%(服务器为4核cpu) <1> 2.问题定位 2.1问题猜测 对于cpu占用率100%的情况,产生以下两种猜测: a. 程序长时间占用系统IO,导致CPU占用率100% b.程序存在严重内存泄露,导致jvm频繁执行full GC,从而使cpu占用率提高,造成服务器假死 2.2jvm的内存管理和垃圾回收机制 java对内存的管理主要分为两种:栈(stack)和堆(heap) 方法区,程序计数器等不做讨论 stack: 在每个线程启动时由jvm自动分配固定大小的地址,stack内主要保存操作符,值对象(int,float等基础数据类型),和引用对象的指针由于stack固定大小,且主要操作为push和pop,并不涉及到垃圾回收等问题,因此不做展开。 heap:堆在线程执行过程中自动分配大小,大小可以随时改变,主要用于保存对象(Object),对象在结束生命周期结束之后便会由JVM的垃圾回收机制自动进行回收堆可分为3大部分年轻代(Young Generation)、年老代(Old Generation)和持久代(Permanent Generation)。 年轻代:年轻代又可分为3个小区:Eden,两个等大的Survior区(from 和 to)。其中Eden主要存放新建的对象,当Eden区无法再存放更多的对象时,jvm会发起年轻代GC(Minor GC),释放Eden中的对象,Minor GC的特点是发生频率高,执行速度也极快,对系统效率的影响并不是很大。当Eden区中的对象经过一次Minor GC仍然没有被释放时,这部分对象将被移入Survior区(对象可能进入from区,也可能进入to区,有具体算法,此处不做展开)。当Survior区中的对象经历过数次的Minor GC之后仍然存活,将被移入年老代。 年老代:年老代中用来存放从年轻代过来的长时间使用的对象,大部分的JVM内存溢出错误均发生在这个区域。当年老代被过度占用,无法存放下更多的数据时,jvm会发起一次年老代GC(Major GC\Full GC),该类型GC会释放年老代中的资源,虽然该GC触发频率很低,但是对硬件资源的消耗较高,且Full GC过程中会暂停该线程的执行。如果系统中存在内存泄露,频繁的触发Full GC,将会严重的占用服务器资源,造成应用的假死,这也是我之前猜测b的依据。 持久代:持久代中用于存放jvm的反射类等,如class等,此区域对GC的影响不大,也不大会发生内存溢出的情况。 下图是引用网上的一张图片,更形象的描述了heap区的构成 <2> 2.3jstat、jmap实战 ok,在弄清楚jvm的GC机制之后,就有了努力的方向了,为了弄清楚GC具体的工作情况,就要使用到jstat命令了。 jstat(Java Virtual Machine Statistics Monitoring Tool)是jdk自带的监控工具,位置在%JAVA_HOME%/bin 下,命令使用方法为  jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ] 下图是我对系统中tomcat进程的监控情况 <3> <4> 命令中 -gcutil表示统计GC情况,5125为tomcat的pid,10000表示没10s统计一次,5表示一共统计5次 结果中s0为from区,s1为to区,E为Eden区,O为Old区,P为Permanent区,YGC为yong GC次数,YGCT为yong GC执行的总时间,FGC为Full GC次数,FGCT为Full GC总时间,GCT为GC总时间。 上面图<3>为cpu占用率高时的截图,图<4>为正常情况下截图。 很明显的看到GC次数相差不大的情况下,GC耗时存在很大的差距,推测此时系统中可能存在内存泄漏的情况。 为了确定jvm中具体有哪些生存的对象,就需要用到jdk自带的另一个监控工具,jmap了 jmap(Memory Map)用于监控系统内存中存活的对象。 使用命令: jmap -histo:live 5125>> /opt/jmap.txt   (如果要dump所有对象,可以通过命令: jmap -dump:file=a.hprof pid ) 其中5125为pid ,由于数据较多,将数据保存在txt文件中进行分析,下图列出了对内存占用排名前几的对象 <5> 一眼看去,String对象稳居第一,好吧,项目中对String的处理确实有不少问题,但是,排名第三的这是什么东西?! 在代码中一查,这个对象只在一个上传文件中的Servlet中被用到了一次,很明显的内存泄漏! 3.问题解决 很明显,jspsmart这个插件正是内存泄漏的元凶,网上查找资料之后确定,jspsmart由于自身bug,在长时间运行后会产生两个严重问题: a. 客户端在未完成上传时便主动终止了上传操作,此时客户端不再上传文件,但是服务端仍然会占用InputStream,并且不会主动释放,造成cpu占用率100%,猜测a证实 b. 客户上传的文件损坏,在创建File对象时无法找到文件终止标识,因此一直在创建新的File对象,造成内存泄漏。 由此,服务器内存溢出和cpu占用率100%两个问题都找到了关键所在,接下来的工作就像对简单了,使用apache的开源项目commons-upload替换原来的jspsmart来完成文件上传的工作,替换过后,系统资源占用正常,附上bug修复后的jmap截图 <6>

上一篇:代码究竟能写多长
下一篇:jqMobi快速入门

相关文章

相关评论