一句话总结:从问题现象为入口,归结为3类问题进行定位分析:内存满、CPU高、线程阻塞。java
首先先介绍下jvisualvm这款jdk自带的性能工具。一般咱们要定位哪块代码性能差,耗时久,最原始的办法就是在各个方法先后日志打印时间戳并计算耗时,这种方法很繁琐,一般要加不少日志屡次部署才能定位到,我一开始也是这么搞的。而使用jvisualvm工具则能够直接查看整个业务代码调用链中各个方法的耗时及占比,直接就能定界出是哪一个方法性能差,耗时久。linux
操做步骤:点击抽样器页签,点击CPU抽样,前台操做触发代码执行,操做完点击中止,再点击快照。在快照页点击搜索按钮,输入代码入口方法名搜索,结果见下图。架构
咱们来分析下下图,RegionNorthbound.createRegion是北向入口方法,总耗时见右侧5.298秒,其调用了RegionServiceImpl.createRegion方法,耗时4.093秒,那么相减就是RegionNorthbound.createRegion方法自己的耗时。jvm
RegionServiceImpl.createRegion方法调用了CommonDao.saveEntity和RegionServiceImpl.checkRepeat方法,分别耗时0.998秒和0.094秒。能够直观查看是调用的哪一个方法耗时久,性能差。整个方法调用链的耗时都可查看。工具
这在大型系统中很是有用。大型系统中一般业务由业务部门开发,平台由平台部门开发,只提供jar包给业务部门使用。那么当测试出性能问题时,首先要定界出是业务的问题仍是平台的问题,再转给对应部门去修改。业务开发不知道平台的实现,没法查看修改其代码,更不用说去加日志。固经过此工具能够快速定界出问题责任主体。性能
固然jvisualvm除了查看代码调用链耗时,实时监控CPU、内存、线程数,线程dump、内存dump等功能都很是好用。学习
下面开始按问题分类进行定位分析。测试
一:内存问题spa
问题现象:后台报错,前台提示异常或500错误。线程
定位:后台报错的定位思路很明确了,查看日志,这里分两类异常:1、java.lang.OutOfMemoryError: PermGen space异常,此为方法区内存溢出,方法区用来存放class代码,一般解决办法就是调大jvm permSize参数值;2、java.lang.OutOfMemoryError: heap space异常,比较常见的堆内存溢出。固然也能够调大jvm参数来解决,但如果不恰当代码引发的,首先检查下本身写的代码,看哪里建立了大量对象。若检查不出来,则使用jmap或jvisualvm导出内存快照。
分析下图heap dump,这里又分两种状况,若左侧占内存大的类名为com.**.User这种本身定义的业务对象,那在代码中搜索下此类名就能定位到哪里建立了大量此对象。若为String、Integer这种基本类型的对象,则可使用Eclipse Memory Analyer此类工具进一步分析,能够查看内存大对象的线程堆栈,便可查看代码调用方法。
二:CPU问题
问题现象:前台显示卡顿,响应时间长,linux top查看cpu使用率很是高
定位步骤:
一、使用top查看进程pid,java系统一般进程名就叫java
二、使用top -H -p pid查看进程中各线程的CPU使用状况,找出最占CPU的线程pid,注意这里其实就是tid
三、经过步骤2咱们知道是哪一个线程占CPU了,使用jstack pid打印线程堆栈,查看该线程的代码调用方法
四、将步骤2线程tid转换为16进制,由于jstack打印出来的threaddump中tid为16进制,而后在threaddump中搜索,便可找到线程堆栈,这里30725转换为16进制就是7805
这里有个状况要特别说明,若是步骤4查看的占用CPU的线程为java gc线程,一般是因为内存快满才致使jvm频繁gc,进而致使CPU高。固此种状况得按上面提到的内存问题去定位解决。Java架构交流学习圈:874811168 面向1-3年经验 Java开发人员 帮助突破瓶颈 提高思惟能力
三:线程问题
问题现象1:请求响应时间长,性能测试TPS/QPS上不去,查看CPU占用又不高
问题现象2:请求响应直接超时,后台线程相互死锁
定位:线程问题一般打印一次threaddump是看不出问题的,要多打印几回对比才能看出问题。建议使用jvisualvm线程页签实时查看线程状态。查看指定业务线程状态,若长时间处于wait或block状态,则可确认该问题是因为线程阻塞引发的。查看线程堆栈可查看是调用哪一个方法时阻塞的。死锁问题也是相似定位,线程堆栈里会提示在等待哪一个线程释放lock,而有两个线程互相等待即会死锁。
备忘:
jvisualvm链接远程jvm,远程jvm添加启动参数: