赞
踩
进行JAVA程序性能分析的时候,我们一般都会使用各种不同的工具。它们大部分都是可视化的,使得我们可以直观地看到应用程序的内部和运行环境到底执行了什么操作,所以性能分析(性能调优)是依赖于工具的。在第2章,我强调了基于数据驱动的性能测试是非常重要的,我们必须测试应用的性能并理解每个指标的含义。性能分析和数据驱动非常类似,为了提升应用程序的性能,我们必须获取应用运行的相关数据。如何获取这些数据并理解它们是本章的主题。【本章重点介绍JDK中提供的性能分析工具】
操作系统工具及其分析
CPU使用率
% vmstat 1
procs -----------memory---------- ---swap-------io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy idwa
2 0 0 1797836 1229068 1508276 0 0 0 9 2250 3634 41 355 0
2 0 0 1801772 1229076 1508284 0 0 0 8 2304 3683 43 354 0
1 0 0 1813552 1229084 1508284 0 0 3 22 2354 3896 423 55 0
1 0 0 1819628 1229092 1508292 0 0 0 84 2418 3998 432 55 0
上图说明,在1秒内,有450ms CPU是忙的(42%用于执行用户代码,3%用于执行系统代码);其它550ms CPU都是空闲的,CPU空闲可能有以下原因:
上面的第3点常常会带来疑惑,如果应用有事情可做,CPU会执行程序的代码。这个是基本的原则,不仅仅准对Java。比如:我们写了一个Windows下的脚本,就是简单的无限循环,如果执行它,CPU立马就100%了,
如果CPU没有达到100%呢,那么就意味着操作系统还有其它一些事情要做(比如:上例中的打印LOOPING),但是却选择了idle。CPU是idle状态对于应用是没有好处的,如果我们运行的是计算密集型的应用,CPU是idle的,意味着我们需要使用更长时间得到结果。
限制一个程序的CPU:当在有CPU周期的时候运行程序会提升程序的性能。但是有时候我们不想要这样,比如:我们在运行SETI@home,它会消耗所有可获取的CPU,如果我们在工作还好,如果我们在上网,写文档或者打游戏,那影响就很明显。为了解决这个问题,一些操作系统的机制可以人为设定程序使用的CPU;程序的优先级也可以让一些后台程序不会在有更高优先级的程序正在运行的时候消耗更多的CPU。
Java和单个CPU使用率
% vmstat 1
procs -----------memory---------- ---swap-------io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy idwa
2 0 0 1797836 1229068 1508276 0 0 0 9 2250 3634 41 355 0
2 0 0 1801772 1229076 1508284 0 0 0 8 2304 3683 43 354 0
1 0 0 1813552 1229084 1508284 0 0 3 22 2354 3896 423 55 0
1 0 0 1819628 1229092 1508292 0 0 0 84 2418 3998 432 55 0
尽管时间粒度很小(只有几百毫秒),但是当负荷很高的时候,从宏观上看CPU的使用率(每0.5s接收一个请求,处理每个请求的平均时间为225ms)是45%(每半秒内,225ms是忙的,275ms是空闲的)。
Java和多CPU使用率
CPU RunQueue
[root@localhost ~]# vmstat
procs -----------memory---------- ---swap-------io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 1 5619980 811116 219740 19671656 0 0 164 194 0 0 2 294 1 0
磁盘使用率
[signal@keyuanfenxi02 log]$ iostat-xm 5
Linux2.6.32-431.el6.x86_64 (keyuanfenxi02) 2016年06月10日 _x86_64_ (64 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
23.45 0.00 37.89 0.10 0.00 38.56
Device: rrqm/s wrqm/s r/s w/s rMB/s
sda 0.00 11.60 0.60 24.20 0.02
wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
0.14 13.35 0.15 6.06 5.33 6.08 0.42 1.04
从上面的输出来看,使用率只有1.04%,w_await也只有6.08ms,似乎情况很好;但是系统使用了37.89%的CPU时间用在sys上面,而且每秒写入0.14MB的空间,需要写入24.2次,这个显然是不合理的(也就是上面说的数据没有得到很好缓存的情况)。
iostat-xm 5
avg-cpu: %user %nice %system %iowait %steal %idle
35.05 0.00 7.85 47.89 0.00 9.20
Device: rrqm/s wrqm/s r/s w/s rMB/s
sda 0.00 0.20 1.00 163.40 0.00
wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
81.09 1010.19 142.74 866.47 97.60 871.17 6.08 100.00
网络使用率
Java监控工具
基本VM信息
这两个命令打印出的系统变量包括:-D选项变量、动态增加的属性、JVM的默认属性。
调优参数
javaother_options -XX:+PrintFlagsFinal -version
...Hundreds of lines of output, including...
uintx InitialHeapSize := 4169431040 {product}
intx InlineSmallCode = 2000 {pd product}
对于其它参数,我们得在命令行给定,因为一些参数会影响其它的参数,特别是设置GC相关的参数。这个命令会打印出所有JVM参数及其值的所有列表。
% jinfo -flags process_id
%jinfo -flag PrintGCDetails process_id
-XX:+PrintGCDetails
% jinfo -flag -PrintGCDetailsprocess_id # turns off PrintGCDetails
% jinfo -flag PrintGCDetails process_id
-XX:-PrintGCDetails
线程信息
% jstackprocess_id
% jcmd process_id Thread.print
类信息
GC分析
Heap Dump后处理
分析工具
采样分析器
侵入式分析器
这个分析结果和采样分析器的结果,很显然有些不同了。首先,最耗时的方法变成了“getPackageSourcesInternal()”,它占用了13%的时间,而不是采样分析器重的4%;上面还列出了一些其它耗时的方法,可以看到,defineclass1方法根本没有出现。这个工具还可以显示方法调用的次数,和方法每次执行的平均时间。
原生分析器
原生分析器中的采样分析器再次把defineclass1作为热点方法,整个启动过程的总时间为5.041秒,它消耗了0.550秒,大概占了11%左右(明显少于前面采样分析器的报告)。上面的分析报告还有一些之前没有被发现的现象:对JAR文件的读取和解压。很显然,它们和类的加载相关(用其它工具也是同样的结论^_^),但是这里我们可以看到读取JAR文件(通过inflateBytes函数)的I/o操作占用了多少CPU。其它分析工具没有给出这个结果,也许是在Java ZIP库中的native code被这些分析工具当成了阻塞调用,然后被过滤了。
Java Mission Control(远程授权控制)
Java Flight Recorder
JFR概观
我们可以看到,通过上图可以看到:CPU使用率,Heap使用率,JVM信息,System Properties,JFR的记录情况等等。
JFR 内存视图
JFR 代码视图
JFR事件视图
我们可以看到,有非常多的事件;总体上可以分为3类:Java应用事件、JVM事件以及操作系统事件。
由于事件很多,下面主要介绍几种常用的事件,这些事件的一些信息可以通过Jconsole,jcmd等工具获取,但是由于JFR的事件数据直接来自于JVM,它们的信息更详细;下面对事件的介绍分为两行,第一行是工具也可以获取的信息,第二行是JFR特有的信息。
启动JFR
通过Java Mission Control启动JFR
通过命令行启动JFR
预告:下一章将重点讨论Java虚拟机的核心模块:即时编译器(Just-In-Time complier JIT编译器)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。