[转]HP-UX中的Java应用性能调优概述(下)

线程、锁定与争夺
 

Java是一种在程序中可以轻松地创建线程或异步过程的开发语言。但是这可能会给不熟悉多线程程序的程序员带来麻烦。
在应用程序中无限制地创建线程不是个好办法,应该尽量避免。许多应用服务器中间件系统在运行时会依据应用系统的配置,在后台生成成百上千个线程。HP-UX支持在一个进程中拥有许多线程,这些线程的数量取决于HP-UX内核参数搈ax_thread_proc?#30340;值。该值可以通过执行搆mtune?#21629;令来查看,如表14所示。

$ kmtune |grep max_thread_proc

表14.使用HP-UX kmtune命令查看内核可调参数的值
 

幸运的是,我们有多种工具可以在程序执行期间或执行结束后来查看程序中线程的行为或状态。这些工具包括Glance/gpm、Hpjmeter和被称为搆ill ??#30340;方法。下面的内容将对它们详细进行介绍。
图7显示了用户通过Glance/gpm查看特定Java进程(也许在一系列Java进程中)并检查Java程序运行过程中创建的所有线程时的数据图形。下图最左边一列中的TID表示每个线程的TID或唯一的线程ID。
应该指出的是JVM本身在启动时需要11个线程,它们与用户程序代码所需的线程是分开的。
 



图7:在Glance/gpm中通过进程界面查看正在运行的Java程序的所有线程


Java程序员在使用线程时面临的风险包括:
? 创建了太多的线程,超出了操作系统的限制。Java程序中会出现揙utOfMemoryException?#30340;错误信息,或者一个提示线程过多的消息。这个问题非常容易解决。主要方法是在系统上使用Hpjconfig工具来查看内核参数搈ax_thread_proc?#30340;值,并使用SAM(系统管理)工具进行修改。

Hpjconfig工具可以从HP Java网站免费下载。
http://www.hp.com/java
? 一个线程可能长时间占用共享资源,从而导致一些或所有其它的线程不能访问该共享资源,全部处于等待状态。图8显示了一个线程占用了其它线程需要访问的资源时的问题情形。
 

HP-UX版本Java SDK 1.3.1(或以后版本)中的-Xeprof选项为用户提供了关于锁争夺的准确数据,并且该数据可以使用Hpjmeter进行分析。
 


图8:控制多个线程访问资源的操作系统监视器结构

 

线程T1占用了另一线程T2需要访问的资源A的锁。线程T2占用了T1需要访问的资源B的锁。这两个线程进入?#27515;锁?#29366;态,除非一个线程让步,否则程序将不能继续执行。
 

这些问题都与应用软件的设计相关。因此,通过修改软件的结构(涉及重新编译)基本上便可以解决这类问题了。但是,工程师必须使用能够发现这些问题的工具,并通过它们快速发现问题的原因。
 

我们能够获得的有关线程和锁争夺问题的第一个线索来自Glance/gpm的输出。在图9显示的系统图形中,过多的CPU时间被消耗在?#31995;统?#26102;间(较深颜色)而不是?#29992;户?#26102;间(颜色较浅的区域)上。正常系统中的情形应该相反。?#29992;户?#26102;间应该是CPU花费的大部分时间,因为这一时间用于执行应用代码。.

 



图9: Glance/gpm中看到的系统时间使用超出正常的证据
 

这是可能出现了线程和锁定问题的一个迹象。然后我们再次使用Glance/gpm来查看系统上各个独立JVM进程所使用的单个系统调用。
 

我们可以获得关于出现锁争夺问题的单个进程的图像,它可能与下图相似。这里,特定HP-UX操作系统调用(如搒ched_yield?#12289;搆sleep?#21644;搆wakeup?#65289;被调用的次数非常高,超出了Glance/gpm?#32047;计系统调用计数?#19968;列中测量的所有其它调用。这些调用可能因JVM版本的不同而有所差异,但是性能工程师必须在最高被调用列表中查找所有的调用。图10中指向搒end?#21644;搑ecv?#35843;用的系统调用率的箭头表明这些调用的频率远远低于搒ched_yield?#21644;搆sleep?#35843;用。而搒end?#21644;搑ecv?#30340;调用频率应该更高,因为它们在该基于网络的程序中需要完成主要的工作。
 

如果我们解决了这里明显的线程争夺问题(例如,通过围绕轮询(polling)线程和线程池模式重新组织线程设计),我们将会看到非常高的搒end?#21644;搑ecv?#35843;用率。

 

图10:单个进程对特定系统调用非常高的系统调用率 ?可能出现了线程争夺

 

如果设计中每个对网络流量开放的接口都使用一个线程,那么这种情形的问题便会出现。在同时建立上百或上千个网络连接的情况下,这可能会导致在线程争夺上耗费非常高的系统开销。这类问题在过去的设计中已通过实施HP Poll API得到解决。HP Poll API是设计应用的一种方法,以使用较少的线程。该主题不在本文的讨论范围之内。在Java SDK 1.4中也有一个子系统可用于对异步I/O环境中的线程进行更好的控制。


使用KILL ?获得线程数据转储
 

该方法在分析JVM线程时十分简单,但是非常强大。在一个正在运行的JVM进程上使用搆ill?#21629;令和参数?3?#25110;?s SIGQUIT?#19981;会影响正在运行的JVM,只是使它生成一个关于其当时所保留线程的所有信息的详细转储。使用Glance/gpm,或者简单的
損s 杄f|grep Java?br>  

命令来获得我们想要查看的JVM的进程ID。然后下表15中所示的命令将会通过该程序的标准输出通道生成有关线程数据的全部转储。

# kill ? 3493 (if 3493 were the PID of the running JVM)

表15. 在JVM上使用kill ?命令使其进行线程转储
 

在开始调用JVM时,我们还可以将标准输出重新定向到一个文件中。
 

以上的kill命令可能需要用户具有超级用户权限。正在运行的JVM生成的标准输出数据(如果超过一定的大小,可能会被要求重新定向到一个文件),可能与下面的示例相似。

 


图11:在由<PID>指定的运行中的JVM进程上执行搆ill ? <PID>?#21629;令时的部分输出数据
 


图11显示了一个特定的线程(其轻量进程ID,图中lwp_id,为14165)正处于挂起状态,因为它一直在等待锁以访问一个特定的对象(由其十六进制地址指定)。这只是一个较大数据转储的一个较小的快照,但能够使读者了解到这一输出。在该输出中我们需要特别注意的是,一个线程长时间占用访问一个对象的锁,而该对象需要被其它线程访问。这导致整个JVM的速度变慢,从而出现问题。
 

我们可以在问题程序运行过程中多次重复搆ill ? <JVM process identity>?#25805;作,以检查是否是持续的锁定造成了该问题。

但是,在处理拥有大量线程的程序时,这可能会生成非常多的数据。彻底分析所有这些数据并从中找出问题非常困难。作为一个附加的好处,我们可以使用Hpjmeter工具来帮助完成一部分工作。
 

使用hpjmeter工具来检测线程锁定问题
 

分析JVM线程行为的一个更简单的方法是采用HP特定选项朮eprof运行该程序至结束,然后使用Hpjmeter工具分析其输出结果。
 

如果正在JVM中执行的程序能够被完全地终止(即,使用System.exit()或一些适当的关闭过程),那么JVM必须采用如下扩展的分析选项(-Xeprof)来运行。

$ java 朮eprof:file=myfile.eprof ClassName

表16.使用朮eprof选项来运行Java程序,以便在运行中进行监视
 

我们分析生成到文件(例如myfile.prof)中输出结果的工具是Hpjmeter分析工具,它可以通过以下地址免费下载
http://www.hpjmeter.com
 

该工具本身以Java语言编写,因此它可以在任何支持JVM的平台上运行。该工具将读取标准JVM选项朮prof生成的输出文件。但是,如果读取HP JVM特定朮eprof选项生成的输出文件,那么该工具将能够带来更多优势和详细信息。
运行Hpjmeter工具(在HP-UX或任何支持Java的平台上)的命令如下表17所示。

$ java 朿p /opt/hpjmeter/HPjmeter.jar HPjmeter

表17. 运行Hpjconfig工具
 

该免费的工具除了与线程运行时间相关的测量方法以外,还拥有许多有用的测量方法。这些测量方法在下载站点的指南中有详细的介绍。在本文的该部分中我们仅侧重于使用其进行线程分析。Hpjmeter工具生成JVM运行中关于线程状态及其运行时间的图形页面。我们将朮eprof选项生成的文件载入到工具中,然后选择名为揗etric?#30340;菜单项显示线程柱形图,便可以得到以下的图形。



表12.在Hpjmeter工具中显示线程运行时间及其状态的页面信息
 

这使我们能够一次看到所有线程的运行时间,并可以通过双击代表线程的彩色条集中于有问题的某个线程或多个线程,从而进行深入的分析。以上图中的线程0有77.1%的时间在CPU内执行;这是正常的标志。该线程有大约21.4%的报告时间被用于profiler系统开销,只有非常少的时间被用在等待执行或锁争夺上。
 

使用HP的Java SDK 1.3.1以上版本和HPjmeter 1.2以上版本,我们可以获得关于线程争夺问题的非常准确的图形,这些问题可能会降低Java程序的运行速度。
 

除了线程分析以外,Hpjmeter在分析许多其它情况时也非常有用。使用该工具提供的一些测量方法还可以追踪消耗大量CPU和wall时钟时间的方法(method)。这将会在以后的?#26114;贵的方法调用?#19968;章中详细讨论。

线程总结
 

Java程序线程被Java虚拟机映射到操作系统线程,也称HP-UX轻量进程(LWP)。HP-UX中调度单元为单个的线程。每一个线程在Glance工具中都是可见的,例如拥有唯一的LWP编号(LWP ID),使用揟hread List?#29305;性。
 

最初,每个线程优先级的初始值与操作系统中的所有用户进程相同。由于线程在CPU中执行,在正常条件下,其优先级会随着其获得更多的CPU时间而降低。这导致线程在离开CPU时优先级变低。因此操作系统在下一次根据优先级来调度线程时,该线程相对于其它线程可能会处于不利的地位。
 

如果一个特定的Java进程是一台计算机上唯一最重要的用户进程,那么该进程可以通过超级用户干预,在开始或执行过程中被授予最高的调度优先级。这可以分别使用搉ice?#25110;搑enice?#21629;令来完成,或使用Glance/gpm的搑enice?#21151;能。
搉ice?#21629;令如下表18中所示。

# nice ?20 java ClassName (notice there are 2 minus signs)

表18. 使用搉ice?#21629;令运行Java程序
 

搑enice?#21629;令需根据正在运行的Java程序的进程ID来执行,进程ID可以使用損s 杄f?#21629;令或者在Glance/gpm中使用进程列表页面获得。下表19中使用的示例Java进程ID为1234。

# renice ?0 1234 (notice there is 1 minus sign)

表19. 在运行中的Java程序上运行搑enice?#21629;令
 

nice和renice这两个命令在执行时都必须非常谨慎。它们只有在以超级用户身份登录到计算机时才能被执行。这些命令可以改变被调整(reniced)进程中所有线程的优先级。
 

执行以上此类命令的结果是相同计算机上的其它进程与搑eniced?#30340;进程相比将处于不利的地位,可能会比不使用该命令时获得更少的CPU时间。但是,在有些情况下这种折衷是值得的。
 

昂贵的方法调用
 

在Java程序中经常会出现这样的情况,少量的程序方法(method)占用了大部分该程序所消耗的时间或资源。很显然,这些是应用设计时需要调整的主要领域。
 

一些方法(method)可能无需修改应用设计或源代码便可完成调整。第一步是发现这些方法的编号和性能特征。Hpjmeter工具最合适于进行这种分析。
 

Hpjmeter具有独特的优势,它可以免费在所有支持Java的环境中运行。第二,JVM的朮eprof选项可生成供Hpjmeter分析的数据,并且经过特别设计,针对其分析的程序只有最低的入侵影响。
调用Hpjmeter的方法如以上表17中所示。图13显示了Hpjmeter中关于方法调用次数最多的输出。
 


图13.Hpjmeter工具所见的最高Java程序方法调用计数
 

很明显,在图13中Mark.SimSearch.bel()方法在该程序所有被调用的方法中被调用的次数最多。揵el()?#26041;法调用的次数远远超过的所有其它方法的调用。我们可以使用其它的Hpjmeter测量方法,例如揈xclusive CPU Method Time?#26469;详细分析该方法,以检查它是否占用了大量的程序资源,例如CPU周期或其它方面。然后我们对该方法的设计及其在程序中的使用进行一些修改,从而清除该瓶颈。
 

在一些情况下,特别是与Java程序中格式化日期类的对象相关时,我们无需修改源代码本身便可以实现对频繁调用的方法的修改。当Java程序中格式化日期对象使用非常频繁时,方法揷urrentTimeMillis?#25110;揼etTimeOfDay?#20415;可能会出现在Hpjmeter方法调用计数测量输出图形的顶端。
 

在使用JDBC向数据库写入记录或从数据库中读取记录时,日期对象的使用可能会非常频繁。
假设我们已经确定这对程序的性能存在非常严重的负面影响,我们可以使用表20中所示的选项来解决该问题。该选项能够减轻程序执行过程中JVM所使用的日期/时间函数(操作系统中的微小运算)的影响。

$ java 朮X:-UseHighResolutionTimer ClassName

表20. 利用该选项运行Java程序,以减轻计时/日期方法的影响

内存溢出
 

Java开发界中最受关注的问题之一是程序可能因为Out of memory而失败。此时可能会出现一个搄ava.lang.OutOfMemoryException?#25552;示,或者也可能以不太友好的形式出现,例如程序执行发生中断。
Java程序员为新对象分配内存的方式如以上垃圾回收一章中所述。理论上,他们不必要担心程序中的对象一旦完成处理之后很快就会被从内存中清除。
 

但是,除非所有关联到对象的引用都被清除(设为搉ull?#25110;超出范围),否则JVM会认为这些对象在程序执行过程中会被再次使用。这被称为是?#20869;存占用?#38382;题。它与其它语言,如C++中的内存溢出概念有很大的不同。
在C++中,发生内存溢出可能是因为代码出现了以下给出的类型(一个程序中很小的片断)。

ptr = new LargeObjectType(); // where ptr is a pointer of a correct type
// The object is used for some purpose, then it is finished with.
ptr = null;
// The programmer has not used 揹elete ptr?to free space before setting ptr to null

表21. C++中的内存泄漏示例
该问题与Java中的情形不同,因为将关联到对象的引用设定为搉ull?#26159;一个很好的习惯,表明程序已经完成了对象处理。而且,Java程序员没有机会以明显的方式来释放分配给对象的内存,因为该语言中没有揻ree?#25110;揹elete?#36816;算符。在Java中,程序员在处理完对象之后遗漏了将引用设为搉ull?#65292;从而导致了?#20869;存占用?#38382;题。
 

如果该对象非常大,并且还可能引用其它的对象,从而形成一个链,那么这些对象占用的整个内存区域,在对象处于范围之内时将不可用。在执行较长的时间时,为这类行为异常的对象重复分配内存很可能会导致程序出现内存不足。这将会导致JVM在不可预知的时刻以不友好的方式发生中断。
 

Java内存占用问题一般很难解决,除非重新编写有问题的代码片段。纠正这些问题不在本文中进一步讨论。Java程序员正迅速采用各种工具,如Sitraka公司的Jprobe Profiler工具,以便在开发早期检测出这些问题。读者可以参考该工具的指南和文档了解更多信息,[Jprobe]。
 

然而,检测这类内存溢出或占用问题初学者都可以胜任。因此,Glance/gpm工具中的揗emory Regions?#30028;面是非常有价值的资产。性能工程师选择需要检查的进程(JVM通常以搄ava?#30340;名字出现在Glance/gpm的进程列表页面中),然后使用Glance工具来显示关于该进程所使用的所有内存区域的报告。
这将会生成一个与图14相似的窗口。
 


图14. Glance/gpm中显示的特定Java进程所使用的内存区域。
 

如图14中所示,Data RSS和Data VSS(常驻集大小和虚拟集大小)的值表示分配给C程序heap的内存。Other RSS、Other VSS和Private RSS的大小表示该程序中分配给Java程序heap的内存。这些空间或其中任一空间的持续增长,都会使我们相信该Java程序中存在内存占用问题。
 

许多Java程序会在后台调用C/C++程序。通常情况下,分析表明内存溢出或占用问题出现在一些Java程序之下的C/C++程序中。因此我们在查找这类问题时应该分析Data RSS和VSS大小的行为。
 

如果我们监视的程序或程序集需要较长的时间才能表现出其行为,那么程序员将不能看到这段较长时间内以上所示的页面。此时,Glance/gpm工具集中的揳dviser mode?#29305;性将会非常有用。然后我们使用该工具的一个批处理模式,将数据收集到一个文件中以便以后进行分析。
 

例如,下表22中所示的命令能够使Glance/gpm每隔5秒(时间间隔可以指定)写入一次样本,并使用adviser_commands文件中所指定的命令。

$ /opt/perf/bin/glance -adviser_only -syntax adviser_commands -j 5

表22. 在Adviser Mode下使用Glance
这类语法可以在揳dviser_commands?#25991;件中指定,示例如下。
 


表23.Glance Adviser Mod命令文件示例
 


以下图15显示了Glance在adviser mode下运行时的输出示例,其中具有明显的问题





图15:Glance工具在adviser mode下的输出示例,其中具有明显的问题

 


基准性能测试症状
 

Java软件开发套件(SDK)1.3.1在本文撰写时已经包括了HotSpot运行时编译器1.3.1(称为揌otSpot?#65289;。
 

HotSpot技术是用户调用JVM时默认使用的运行时(除非用户指定了朿lassic选项,这在一般情况下应该避免)。它在运行时分析Java代码的行为,并将部分字节代码段编译为一个中间的表达式,并进一步编译为本地二进制代码,从而优化运行。在Java程序运行过程中的某些情况下,Java字节代码的执行可以在HotSpot的控制下从已解释的形式转换为已编译的本地代码。该?#32534;译?#27969;程的一个重要条件是重复执行一个拥有许多后向分支或循环的方法。
 

在分析一些基准性能测试的结果时,我们发现一些基准性能测试在HotSpot默认JVM下的速度似乎比在其它JVM下的速度要慢。这是HotSpot运行时在?#39044;热?#38454;段的一种症状,它需要利用这段时间来检查一个方法被频繁地执行,并存在合适的逻辑类型供HotSpot将其编译为本地代码。
 

该现象一般可以通过将应该被优化的方法放置到一个循环中来解决。这会使HotSpot运行时编译器真正地对其进行编译。该技巧能够使部分基准性能测试的执行时间出现呈数量级的提升。
 

这类情形的示例是,程序中的搈ain?#26041;法完成所有的处理,并且从不调用另一个方法。示例如表24中所示。
 

表24. 不能从HotSpot运行时编译中受益的程序示例
 


请注意在表24中,搈ain?#26041;法完成了所有的工作。HotSpot运行时编译器没有机会对代码进行优化,从而允许执行编译过的代码,而不是字节代码。表25中的示例程序也完成同样的工作,但是它的运行速度比其等价程序更慢。
 



表25. 能够从HotSpot运行时编译中受益的程序示例
 

这里可以看到,重复10000000次的揵ig?#24490;环现在包含在一个方法中,并且在本身循环内被该类的搈ain?#26041;法调用。搑unTest()?#26041;法在10000000次重复循环中包含了大量的后向分支,并且本身被从搈ain?#20013;反复调用,因此它完全适合在JVM固有的HotSpot运行时编译器中进行运行时编译。所以,它的运行速度比表24中等价的程序要快很多。
该现象在HP Java性能调节网站上的另一篇单独的文章中有更加详细的介绍。
http://devresource.hp.com/devresource/Docs/TechPapers/Java/HotSpotBench.html
读者可以参考该网站了解关于本主题的更多信息。

结论
 

本文中所介绍的工具和技巧能够帮助工程师调节Java程序的行为,以获得更高的性能。性能工程师不应该因初始测试中获得的较差结果而感到气馁。最初结果之下的问题通常都可以被解决,从而获得更好的结果。
 

在采取任何措施修改程序的运行时性能之前,必须首先使用Glance/gpm、Hpjmeter和HPjtune等工具来对垃圾回收进行分析,进而对可能影响性能行为的问题作出诊断。OpenView Transaction Analyzer工具也能够就基于J2EE的应用中可能存在的性能瓶颈点提供非常有用的分析和诊断。
 

我们建议按顺序进行体系结构评估、测量、数据分析、瓶颈确定、逐步调节和重新测试的流程。本本介绍了初学者如何使用HP工具来检查各个领域的问题,特别是
?内存管理
?线程行为
?系统与JVM配置
?程序资源占用

因为这些问题在调节Java应用的性能时能够带来富有成效的结果。
参考文献

[Sauers] Sauers, R. and Weygant, P., HP-UX Performance Tuning, HP Press
[Shirazi] Shirazi, J., Java Performance Tuning, O?Reilly Press
[Halter] Halter, S. and Munroe, S., Enterprise Java Performance, Sun Microsystems Press
[Wilson] Wilson, S. and Kesselman, J., Java Platform Performance, Addison Wesley
[Austin] Austin, C. and Pawlan, M., Advanced Programming for the Java 2 Platform, Addison Wesley
http://www.Javaperformancetuning.com/

工具

性能分析工具

HPjmeter http://www.hpjmeter.com ?免费下载
Glance/gpm 包含在HP-UX应用工具光盘中
HPjconfig http://www.hp.com/java ?免费下载

Jprobe http://www.sitraka.com
Introscope http://www.wily.com
OptimizeIt http://www.intuisys.com

负载测试工具

LoadRunner http://www.mercuryinteractive.com
SilkPerformer http://www.seque.com
e-Load http://www.empirix.com

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值