1. 介绍
在Java的广泛应用中,一个关键驱动因素是由于使用标准类库和应用框架从而提高了 生产效率。通过减少必要的设计,实现和调试等软件开发任务,Java在各种平台之间极大地改善了集成性和互操作性;其它的开发环境都不能提供像Java那 样的强大功能。实际上,没有一个环境像J2EE那样具有明显的基于框架开发的优点,J2EE能够快速地构建可扩展,分布式的安全企业级应用。
虽然这些优点一直在促进J2EE的空前发展,但也经常出现一些麻烦,那就是人们经常 对J2EE应用的性能感到失望。因此,我们需要一些工具和调查策略来帮助J2EE开发团队解决这些性能问题。这就是Quest JProbe Profiler和Jprobe Memory Debugger所要解决的问题。
1.1 J2EE性能概揽
一般情况下,最终用户对J2EE应用性能的体验与下面层次是紧密相关的:
J2EE体系结构图
虽然毫无疑问,底部层次会影响整个性能,经验也不断地表明,性能下降的普遍原因是由组成J2EE应用的Servlets,JSPs和EJBs的设计问题和不佳的实现造成的。本文将集中讨论在这个底层中如何识别出性能下降的原因。
1.2 概述
本文描述了在BEA WebLogic Server6.1上下文环境中,怎样用Quest JProbe Memory Debugger和Profiler分析J2EE应用。包括三个主要部分:
2. 集成BEA weblogic 服务器和Quest JProbe
2.1 Quest JProbe
Quest JProbe产品线由一族工具组成,该族工具包括下面四个分析工具。
虽然本文集中讨论了JProbe Memory Debugger和Profiler,但所有四个工具都采用了相同的体系结构设计,并且与BEA WebLogic服务器的集成方法是相同的。
2.1.1 JProbe的体系结构
一个基于JProbe的调查会话由两个程序组成:
图2 JProbe体系结构
JProbe控制台是一个基于Swing的Java应用,它提供了用户图形界面(GUI),用于建立调查会话,在程序运行时查看分析信息和深入分析Snapshot文件中的信息内容。
测试型Java虚拟机-JProbe通过JVMPI(Java Virtual Machine Profiling Interface)提供的回调方法,使用标准的Java虚拟机运行Java应用并收集分析信息,该虚拟机是由厂商提供的。在剖析基于WLS的J2EE应 用中,Java应用运行在Java虚拟机中,该虚拟机由WebLogic服务器的基本框架组成,就象J2EE应用部署到上面一样。
这种结构具有非常灵活的启动方式。你可以从用户图形界面本身启动测试型Java虚拟机,也可以单独启动测试型Java虚拟机并且使它连接上JProbe控制台。
2.2 使用JProbe Application Server Integration Tool
1. 启动JProbe Application Server Integration。
2. 从左上角下拉列表中选择你要集成的BEA Weblogic服务器版本。
图3 JProbe Application Server Integration窗口
3. 点击"Create"按钮。编辑窗口右边的内容,如图3所示。
4. 编辑下面区域或使用默认值。
Integration ID: | JProbe Demo 1 | Integration ID,便于重用每次集成过程 |
Server Directory: | D:\bea\wlserver6.1 | 直接输入WLS服务器根路径或者通过"浏览"方式输入。 |
Domain Name: | Mydomain | 输入你想分析的域名。 |
Startup Script: | StartWeblogic.cmd | 直接输入要调查的服务器的启动脚本或者通过"浏览"方式输入。 |
JProbe Settings:(JPL File) | check the VAR checkbox | 集成工具允许你使用先前创建的JPL(JProbe Launchpad)文件。如果要使用由每个工具在启动时默认创建的JPL文件,选择VAR复选框。 |
Java Executable: | d:\sun\jdk1.3.1\bin\Java.exe | 可直接输入或通过浏览方式输入Java虚拟机的执行文件路径。 |
5. 点击"Advanced>>"按钮。
6. 填写下面这区域。
Java Options: -classic -mx128m -ms64m 有选择地给Java虚拟机输入参数。
7. 点击"Save"按钮。
图4. JProbe Application Server Intergation窗口
你已经成功创建和BEA Weblogic6.1的集成, 所有四个工具都可以使用这个集成过程。
8. 点击"Close"按钮。
3. 识别J2EE应用性能下降
JProbe Memory Debugger能帮助你追踪到游离对象(loitering objects)和减少创建过多的对象,并且JProbe Profiler能帮助你发现性能瓶颈。根据具体情况,需要具体分析。在这里,我们简单地概括用于解决对象循环和性能瓶颈这两个常见问题的步骤。更多的信 息和其它使用JProbe Memory Debugger和Jprobe Profiler的方法,可以参考在线帮助或者阅读JProbe Memory Debugger Guide和JProbe Profiler Developer's Guide。
3.1 对象循环(Object Cycling)
Java应用性能下降的一个主要原因是创建过多的对象 (或称为对象循环)。Java虚拟机分配了过多的内存,创建了不必要的对象并对这些对象的初始化,加大了垃圾回收活动,从而引起性能下降。
作为一个性能分析人员,你首先需要识别出创建大量短期对象的方法。这些方法是进一步 做减少创建对象数量分析的理想入手点。JProbe Memory Debugger提供的一个垃圾监视功能可以把对象和分配它们的方法连接起来,并且当你的应用运行时,可以追踪有多少对象已经被垃圾回收了。
3.1.1 启动JProbe Memory Debugger的研究会话
1. 启动JProbe Memory Debugger。当欢迎界面出现的时候,点击"Run"开始启动。
图5.JProbe欢迎界面
2. 在JProbe LaunchPad窗口中:
a. 选择"Using Application Server"
b. 从"Application Server"下拉的菜单中选择BEA Weblogic6.1
c. 注意在"Integration ID"下拉的菜单中填写JProbe Demo 1
3. 选择"Filter"
a. 点击"Please enter a package,or method to display data for"。输入你要调查的包:profiler.com.quoteme.stockwatch
b. 在"Display"栏的下拉菜单里选择"Display"
4. 选中"Monitor Garbage Collections from Program Start"复选框。
5. 选择"Snapshot Directory:"为d:\temp。
6. 点击"Run"按钮。
图6.JProbe LaunchPad Pad窗口
当WebLogic Server初始化时,Runtime Heap Graph将增高,这反映了对象创建和垃圾回收活动。一旦WebLogic Server已经被充分初始化后,你就可以开始着手分析了。
3.1.2 运行时交互
一旦WebLogic Server已经充分初始化,选择你想要用于分析对象循环的应用用例。选择Grabage Monitor标签,按下面的步骤:
1. 首先运行一次Garbage Collection ,回收在Java堆中分配的,但不再使用的对象。Garbage Monitor表随时更新反映这些被回收对象的情况。
2. 点击"Clear Table"清空Garbage Monitor表。
3. 运行你的应用用例。当Java虚拟机开始垃圾回收时,Grabage Monitor表将随之更新。
提示: 在Heap Usage Chart中寻找负载峰值。急剧升降的负载峰值意味着一些对象在被垃圾回收之前只存活了很短的时间。连在一起的一些急剧升降的负载峰值是一个明确的信号,意味着是一个对象循环问题。
4. 在完成你应用用例后,再次运行Garbage Collection ,回收最后分配但不再使用的对象。
3.1.3 分析结果
当会话结束时,Garbage Monitor中包含了已回收最多实例的前十个类。通常,这些类不是你自己应用的类,准确地说,它们是被你的一些方法(直接地或间接地)分配的第三方的类。最后一列是分配这些已回收对象的方法名。
提示: 如果被不同方法分配的实例属于同一个类,并且都是前十个类的话,你将见到两行相同的类。
1. 使用Filter Allocating Methods,只显示你包中的一些方法,屏蔽掉其它包中的方法。在我们的例子中,客户J2EE应用定义在 profiler.com.quoteme.stockwatch包里面,所以我们把过滤规范 profiler.com.quoteme.stockwatch.*.*输入到Filter Allocating Methods文本输入控制中。
2. 在GC'ed列中,你能看到你的方法分配了多少实例。作为比较,查看Alive列就能看到还有多少实例仍在堆中。Java开发者通常会对创建和移走了多少对象而感到惊奇。
3. 现在你已经识别到你有问题的方法。想想你可能怎样修改这些分配对象的方法,从而减少或排除对象循环?例如,你可以尝试重用某个对象或者创建一个可重用的对象池。
4. WebLogic Server6.1编译JSP后,自动产生了一个servlet类名,并赋予一个包名和类名。例如,如果有一个名为TestJSP.jsp的JSP文件, 将被编译成名为jsp_servlet.__testjsp的类(JSP名跟着两个下划线,并且都是小写字母)。
用Filtering Classes为jsp_servlet.*限制Garbage Monitor中的内容,可以看到已经被垃圾回收到Garbage Monitor中的JSP。在Filtering Allocating Methods设置jsp_servlet.*.*或jsp_servlet._<你的JSP名>.* 限制Garbage Monitor中的内容,可以从分配的角度在指定的JSP中查看垃圾回收对象。
更深入的研究
如果你分配的方法没有一个出现在Garbage Monitor中,或者在修改明显的问题后,仍然有对象循环的问题;你需要进行堆栈跟踪,检查哪个方法的调用导致了创建实例并分配了空间。需要使用 heap snapshot查看堆栈跟踪。要了解更多的信息,请看在线帮助里的Garbage Collection Tutorial或者JProbe Memory Debugger Developer's Guide。
3.2 性能分析
解决对象循环问题有助于性能的改进,但你可能仍然面临着性能瓶颈。进行一次性能分析可帮助你在J2EE应用中识别低效率的算法。JProbe Profiler提供了应用的方法级和源代码行级度量值。
3.2.1 启动JProbe Profiler调查会话。
1. 启动JProbe Profiler。当欢迎界面出现时,点击"Run"开始。
图8 JProbe欢迎窗口
2. 在JProbe LaunchPad窗口中:
a. 选择"Using Application Server"
b. 从Application Server下拉菜单中选择BEA Weblogic6.1
c. 注意在Integration ID下拉菜单中填JProbe Demo 1
3. 选择Filter
a. 点击Please enter a package,class,or method to display data for。输入你要调查的包profiler.com.quoteme.stockwatch
b. 从Detail Level列的下拉菜单中选择Line Lever
这个元素定义了我们想要把所有运行在环境中的Java软件看作基础结构。因为我们不想详细了解它们的性能信息 (我们只是想知道在代码上的影响,我们不想更细地分析)
提示:在WLS6.1中的JSP Profiling当JSP被WebLogic Server6.1编译时,产生的servlet被给予一个产生的包和类名。例如,如果有一个名为TestJSP.jsp的JSP文件,它被编译后,生成 名为jsp_servlet._testjsp的类(两个底线被JSP名跟着,都是小写字母)。 如果你想跟踪你的JSP里的方法在执行中花了多少时间,你必须指定正确的过滤策略,用于捕获数据。
4. 选择"CPU Time"
5. 选择"Record Performance at Program Start"复选框
6. 选择"a Snapshot Directory:"为d:\temp
7. 点击"Run"按钮
图9 JProbe Profiler LaunchPad窗口
3.2.2 运行时交互
在性能分析中,Heap Usage Chart就象一个执行进度的监视器,与上节介绍的Garbage Monitor不同,这里不提供类似的运行时性能信息。使WebLogic Server自己初始化到完全启动。
作为对象循环分析,我们推荐使用应用级的,以用例为中心的方法进行性能分析,具体如下:
1. 清空累积的性能数据 。
2. 运行你的应用用例。
3. 执行一次性能快照 ,保存性能信息。
性能快照包括时间和在用例运行期间对象创建等度量数据(这个运行期间从重新设置性能信息开始-第一步,一直到执行快照结束,第三步)。
3.2.3 解释结果
JProbe Profiler提供两个工具,以不同的格式显示收集到的数据;可根据具体情况选择:
3.2.3.1 Time and Object Creation Metrics
JProbe Profiler在方法方面收集了三个基本度量值:
在这些基本的度量值基础上,JProbe Profiler计算出两种度量值表示方法调用树:
基于Number of Calls用四种平均度量值:
在默认情况下,Call Graph显示的数据是在性能快照中的数据。我们建议你关闭Call Graph一会再打开Method List窗口。
3.2.3.2 Method List
Method List窗口(见图10)以表的形式显示性能数据。
图10 JProbe Profiler Method List窗口
每一行显示了方法的时间和方法创建对象的度量值。使用Method List能很快识别你最耗时的方法。通常你会发现你的性能瓶颈和这些方法有关。
如果你是第一次调查,跟着下面这些步骤将使你能更有效地使用Method List。
1. 选中你的snapshot,打开"Method List"。
2. "Filter"区域只用于显示在你包中或在你感兴趣的类中的方法。
3. 点击"Method Time"列名,把你最消耗时间的方法排在最前面。仔细查看前十个。是不是有一些度量值令你惊讶?你能改进你方法中的算法吗?
4. 点击"Cumulative Time"列名,把最消耗时间的调用树排在最前面。比较一下"Method Time"和"Cumulative Time"。虽然方法本身可能效率很高,但也可能调用了低效率的方法,这些低效率的方法可能在你的代码中,或者在第三方的包或应用框架中。
5. 点击”Number of Calls”列名,查看一下你哪个方法被调用最多。如果一个或多个度量值同时反映这些方法是低效率的,需要考虑减少调用这些方法,或调用那些效率稍好的方法。
3.2.3.3. Call Graph
Call Graph(见图11)提供一个非常有力的方法调用关系视图。它把J2EE应用放到WebLogic Server上下文环境中,所以你能看到WebLogic启动的所有线程,包括调用J2EE应用的线程。为了方便查找,Call Graph下面有"Method List"。
当分析性能时,在定位J2EE应用的入口点和排除与WebLogic线程有关的数据方面, Call Method是最有效的。在分离出应用的数据基础上,可快速画出执行流程,并用图形清晰地显示出来。
下面是使用Call Method的有效技巧:
1. 选中你的snapshot,打开"Call Graph" 。
2. 点击"Find"并且定位你的J2EE应用的入口位置。 通常是servlet中的doGet()或doPost()方法。
3. 选择方法并分离出数据形成图形 。
4. 显示方法的一个子集作为开始,这些方法按照"Cumulative Time"排序是最耗时的方法。当你分析一个方法,在方法的调用树上将增加额外的节点。
5. 在"Method List"中,根据你发现的瓶颈位置,在"Color By"的下拉列表中选择相同度量值。根据你选择的度量值,现在最耗时的方法都以鲜艳的颜色突出显示出来。
6. 选择最耗时的方法。展开父方法树(通过点击节点部分或节点左边部分的空箭头记号),就能看到哪个方法调用它了。你可以调用不同的,耗时比较少的方法吗?你需要经常调用这些方法吗?
7. 展开子方法树(指向节点的右边),可以看到调用了哪个耗时的方法。还有哪些子方法也是耗时的呢?你意识到第三方的方法实际的耗时情况吗?你能调用一个实现了更有效率算法的不同方法吗?
图11 JProbe Profiler Call Graph窗口
3.2.3.4 Method Detail View
从Method List或Call Graph中,你都能深入地分析,在一个视图中很方便地看到耗时的方法的度量值,还有它们子方法和父方法的度量值。选择方法并打开"Method Detail View" 。
"Method Detail View"(见图12)在窗口的中心显示了选择方法,它的父方法在上面,它的子方法在下面。我们对列的头部已经熟悉了,它们和你在其它工具中看到的度量值 相同。一个重要的区别是:用于显示父方法和子方法度量值表示对所选方法的贡献值,不是对它们自己的度量值。所以,如果一个方法被调用了12次,这些调用它 的方法,和12次调用分别显示在父方法的图中。如果你想继续分析父方法或子方法,双击该方法,使该方法在"Method Detail View"的中心显示。
图12 JProbe Profiler Method Detail窗口
3.2.3.5 Source Window
要查看你方法中的代码,选择方法并且打开Source Window。你需要指出你的源代码具体位置。
如果你是按行收集数据,你能在Source Window(见图12)中看到这些数据。在左列中,显示了每条语句的数据度量值。行级度量值是方法级度量值的细化,包括调用次数,执行该行的时间,执行该行时创建的对象数量,累积时间和累计对象数量。
提示: 如果需要编辑你的代码,并且已经把集成开发环境IDE和 JProbe Profiler集成在一起了,你可以通过选择Edit>Edit Source打开你的集成开发环境。当然,需要运行你重写的代码,并建立新的JProbe Profiler分析会话时,你做的改变才反映在JProbe Profiler上。
图13 Jprobe Profiler Source Window