版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、HP-UX中的Java应用性能调优概述HP-UX中的Java应用性能调优简介本指南旨在为读者提供一系列有用的方法来排除与Java相关的性能问题,并帮助在HP-UX系统中进行Java应用的性能调优。本文并没有详细地讨论这一课题,只是为该领域的工作进行了概述。参考资料部分提到了几本关于Java性能调优相关的书籍和参考文章,可以参阅它们来了解更多详细信息。本文的内容与包含HotSpot Runtime编译器版本1.3.1的Java Software Developer Kit(SDK)1.3.1及以后版本保持一致。文中讨论的许多主题,在下面的网站有更加详细的分析 HYPERLINK /dspp /d
2、spp(搜索“Java Performance Tuning on HP-UX”)或直接访问 HYPERLINK /dspp/tech/tech_TechDocumentDetailPage_IDX/1,1602!0!,00.html /dspp/tech/tech_TechDocumentDetailPage_IDX/1,1602!0!,00.html在许多报告有性能问题的情况中,对垃圾回收行为的调查表明JVM运行的heap配置存在问题。在其它情况中,也可能是应用的线程锁定或内存溢出引起了该问题。我们建议初学者采用以下方法的结合来解决JAVA应用性能的问题:使用Glance/gpm工具来找出
3、瓶颈所在分析Xverbosegc(来自垃圾回收器的详细报告)JVM选项的输出结果;使用Hpjmeter工具分析Xeprof(扩展的简档描述)JVM选项的输出结果;浏览kill 3 命令的几个输出结果它们将提供有用的数据,可以帮助您对碰到的问题进行彻底的初始分析。本文将会对这些领域进行深入的分析。以上所述四种方法,以及对硬件设置、操作系统和JVM版本及选项的详细描述,是性能工程师着手解决问题时最初的一些步骤。Glance/gpm是一个HP的工具,在HP-UX Application Software光盘的软件包中。它也可以用于其它操作系统,例如Solaris和AIX。其它工具,如“top”、“v
4、mstat”、“netstat”和“sar”也提供了类似的性能信息。这些均被记录在Sauers和Weygant Sauers所著的HP-UX性能调优一书中。鉴于本文的目的,我们将侧重于介绍使用Glance/gpm进行系统和进程层的监视。采用系统化的方法Java性能分析中存在许多的不确定因素。HP-UX内核参数、在运行时指定的JVM选项以及应用设计等所有一切都会带来相应的影响。正是由于该原因,所以在分析性能问题时应采取从上至下系统化的方法(从最外层的系统角度)并在首次分析时考虑所有的可能性,这一点非常重要。采取从上至下的方法,我们首先将系统作为一个整体来考虑(将一台或多台协作的计算机作为一个集合
5、,它们互相之间具有网络影响,可能在某些点还存在数据库访问影响)。在考虑了整个系统中所有的可变因素之后,我们将分析范围缩小到单个计算机,再进一步缩小到该计算机中的单个进程,从而找出问题的根本原因。之所以采用从上之下的分析方法,是因为导致性能问题的原因可能存在于程序、计算机、数据源和网络等构成整个系统的各个部分。有多种工具可以帮助我们逐一分析每台计算机,HP-UX Glance/gpm便是其中最强大的工具之一,本文后面的部分会再次提到该工具。过去,研发实验室进行的分析工作发现性能瓶颈的原因也可能源于非Java的技术。性能工程师必须时刻考虑到这一点。系统中各台计算机之间以及计算机与其外部数据源之间的
6、数据交换也必须进行检查。这项工作可以通过使用“netstat”等网络与数据库监视工具来完成。推荐流程中的步骤包括:评估整体的系统配置、吞吐量和负载情况;测量性能(使用我们将进一步详细介绍的工具);分析来自性能测量工具的数据;确定一个或多个可能的瓶颈;每次仅更改或调节一个项目;再次测量性能以检查该调节步骤所带来的变化。在本文以后的章节我们将会更加详细地分析这些步骤。在分析过程中考虑来自多个工具的数据并反复核对其输出结果也非常重要。例如,Glance/gpm生成的线程信息应该与将“kill 3 ”命令应用于JVM进程时所看到的线程数据一致。较高的吞吐量水平并非总是性能问题的原因所在。许多生产系统在
7、运行时都一直保持高容量的交易流。性能工程师所要面对的真正问题是“进程中的瓶颈在哪里,并且它们如何被触发?”为了找出这些瓶颈,有时候需要为系统添加负载,再现峰值用户处理水平时的负载,这时候系统将非常繁忙。有多种工具可以在基于Web的应用上实现这种高负载,它们将在本文最后的工具章节中介绍。避免在信息不充分的情况下妄加猜测不经过分析和测量便对问题原因作出最初的猜测非常具有诱惑力,特别是在项目小组承受着压力要解决一个问题时。这种情况应该避免。通常情况下,我们所作的猜测会造成误导。相反,我们建议先使用各种工具(Glance/gpm、Hpjmeter、Hpjtune、sar、Xverbosegc和Xepr
8、of的JVM选项等等)来收集性能数据,在这些工具的数据经过分析并被了解之后,便可以就所见的症状给出原因了。该分析需要一定的时间,通常性能工程师进行性能调优的第一步是先搜集系统运行数据,而不是上来就修改系统参数。准备一个修改记录非常重要,用于记录所作出的每一个变更,以及应用变更后所带来的性能影响。性能工程师非常容易对系统一次进行多个变更,这种情况应该避免。因为多个变更、多种结果以及许多的外部影响因素很容易给工程师造成混乱,所以应该以书面的形式将所应用的变更记录下来。测试大型应用具有代表性的较小样本计算机编程中的一个常用故障排除技巧是将问题尽可能分解到能够反映症状的最小代码块。但是这种方法在性能分
9、析中却非常危险,因为较小样本的行为通常与实际生产系统有很大差别。建议尽可能在“真实的”系统上进行性能分析,而不是采用大型系统的子集。这可能会占用测试的时间,但是所获得结果的将会更加准确。在分析一个系统时,测量工具本身确实也会对性能产生影响。例如Glance/gpm便是HP-UX系统中的一个进程,它会占用该机器的一部分CPU资源。我们所使用的工具已经尽可能使这种影响将到最低。但我们在使用一个测量工具时,这种影响总是存在的。将系统作为一个整体进行评估当前许多基于web的体系结构可能采用一组计算机作为web服务器层,另一组计算机作为应用服务器层以及一个数据库层。所有这些都通过网络连在一起,并互相作用
10、以响应每一个客户请求(例如通过浏览器发出的请求)。进行整体系统评估的主要工具有Glance/gpm(图形进程监视)以及类似的工具(如HP PerfView),它能够显示单个计算机中操作系统和进程的状态。Glance/gpm将就计算机不同组件的状态为工程师提供一个可视、直观的评估,例如其CPU负载、输入输出负载、网络流量,以及内存消耗率等。在每台HP-UX计算机上使用Glance/gpm工具使工程师能够清楚地看到参与整个系统的所有机器中哪些负载紧张,哪些比较空闲。下图显示了Glance/gpm窗口中最顶层的计算机视图,我们可以看到该计算机的“系统时间”消耗水平非常高,而被使用的“用户时间”水平非
11、常低。这表明该计算机存在问题。实际上我们希望有更高的CPU消耗被用于“用户时间”(用于执行应用的时间),而不是“系统时间”(用于执行操作系统功能的CPU时间)。机器中出现这种非常高的“系统时间”占用率可能是由于操作系统调用,它们负责锁定被称为“mutexes”的数据结构,占用很长的系统时间来解决争夺,或者等待访问这些结构的线程被强制进入休眠状态。因此以下的情况可能是Java程序中的线程锁争夺所引起的,该话题将在本文以后的部分深入讨论。到目前为止,我们已经知道太多的时间被用于执行系统代码,而不是应用代码。下一步是检查机器中的哪一个特定进程造成了这种情况。图1:HP-UX中Glance/gpm工具
12、的主窗口Glance主窗口 高系统时间举例低用户CPU时间高系统CPU时间从整体系统视图缩小至单个计算机,再进一步缩小至特定的进程是使用Glance/gpm工具以及其它HP-UX性能分析工具的一个练习。它们将在参考1Sauers中详细描述。数据收集性能分析的第一个步骤是记下用户交易执行路径中每一台计算机的机器设置(从而找出怀疑对象)。我们需要的信息包括:计算机中CPU的数量以及这些CPU的速度(CPU的数量可以中Glance/gpm中看到)物理内存的大小(也可以在Glance/gpm中看到)磁盘空间的大小(已占用和可用的容量,在“df”命令的输出结果中)操作系统可调节参数的值(使用Hpjcon
13、fig工具可以看到)需要的操作系统补丁(Hpjconfig也能提供帮助)使用的JVM版本(使用“java version”命令可以找到)使用的JVM选项(如Xms、-Xmx或其它)。以下表1中是“java version”命令所输出的Java版本信息的举例。 Java version 0-releaseJava(TM) 2 Runtime Environment, Standard Edition (build 0-release-010607- 16:53-PA_RISC1.1)Java HotSpot(TM) Server VM (build 1.3.1 0-release-010607-
14、19:35-PA_RISC2.0 PA2.0, mixed mode) 表1. “Java version”命令输出的Java运行时版本信息以上的每一个值均能帮助性能工程师测量机器中Java程序的性能特征。只需简单地升级至最新的Java SDK版本,升级操作系统并应用最新的补丁,或者使用Java运行时的正确选项,便能够解决一部分性能问题了。建议性能工程师先升级至最新的Java SDK版本和最新的补丁,以证明这样是否能够改善系统的状况。下一章(“hp-ux内核参数”)中描述的Hpjconfig工具也能够检查是否已经应用了正确的HP-UX补丁。表2显示了Java虚拟机的一种误用情况。该实例显示了用
15、户使用了较旧、未经优化的Java运行版本(“classic JVM”),它不适合用于服务器端长期运行的应用。建议在这种情况下使用默认的Java运行(“HotSpot JVM”)。 $ java classic ClassName表2. 使用较旧、低效的Java运行时版本 这种情况应该避免。hp-ux内核参数对操作系统进行正确的设置,使其以最优的方式来运行Java程序极其重要。几个HP-UX可调参数会影响这一正确的设置。用于确定这些可调参数最佳值的工具是Hpjconfig,它本身也是一个Java程序。Hpjconfig是一个免费的程序,可以从以下网址下载 HYPERLINK /products1
16、/unix/java/java2/hpjconfig/index.html /products1/unix/java/java2/hpjconfig/index.html。表3显示了Hpjconfig的调用。$ java cp HPjconfig.jar:HPjconfig_data.jar HPjconfig表3. 使用Hpjconfig工具该工具首先检查运行其的计算机的型号,然后允许性能工程师来选择各种不同的应用类型,例如“应用服务器”、“Web服务器”和“WAP服务器”等。随后它将就某些HP-UX内核可调参数应该采用的值提出合理的建议。它还能够将输出结果数据保存在一个文件中。然后系统管理
17、员便可以使用SAM系统管理工具将这些推荐的值应用到操作系统中。图2显示了Hpjconfig的初始界面。此时,工具正在检查应用到当前HP-UX系统中的补丁是否适合于Java。性能分析流程Hpjconfig:检查补丁图2:HP-UX系统中Hpjconfig工具的主界面图3显示了针对特定应用类型所推荐的内核参数举例,如Hpjconfig工具中所见。性能分析流程Hpjconfig:内核参数更新至推荐的值图3:Hpjconfig工具的HP-UX内核参数窗口了解有关这些参数进一步的详细信息,请访问中国惠普公司技术动力社区并在技术论上进行交流: HYPERLINK 27/partnerportal/solu
18、tioncommunity.aspx 27/partnerportal/solutioncommunity.aspx请注意Hpjconfig窗口“推荐的调整值”一列中所显示的值仅仅是一些建议。如果一台计算机上运行了多个应用进程或数据库进程, 那么HP-UX内核可调参数的最优值将需要在Java程序以及共享这台机器的其它程序之间实现平衡。对Java程序最为重要的具体HP-UX内核可调参数包括:max_thread_proc 决定任何单个进程中所允许的最大线程数量;maxdsiz 决定任何进程的数据段大小;maxfiles 为任何进程能够打开的最大文件数量指定一个软限制;maxfiles_lim 为
19、任何进程能够打开的最大文件数量指定一个硬限制;ncallout 决定I/O等待的最大超时值;nfile 决定计算机系统中所能打开的最大文件数量;nkthread 决定计算机系统支持的最大内核线程数量;nproc 指定计算机系统中所允许的最大进程数量垃圾回收Java程序需要一定的对象,它们运行时将会占用部分内存。这些对象可能在程序开始运行时创建,也可能在程序运行过程中创建。在创建一个新的Java语言对象时,分配给它的内存将被放置在一个被称为“heap”的区域。该heap内存的大小是有限制的。对于任何JVM运行其默认最大值被设定为128MB,除非用户使用JVM选项mx或Xmx调整了最大值。以下命令
20、将以默认的heap大小值来运行JVM(未指定选项)。$ java ClassName(ClassName是该应用的开始类)表4. 以默认的128Mb最大heap值运行Java以下命令限制该第二个JVM运行至多占用240MB的heap大小。 $ java Xmx240m ClassName表5. 带有240Mb最大heap值的Java运行在第二个程序试图为对象分配内存(创建新的对象)时,如果对象需要占用超过240Mb的内存,那么JVM将会产生一个异常信息“OutOfMemoryException”,程序的执行便会终止。Java程序与C或C+程序不同,它不会显式地重新分配或释放占用的heap内存(
21、而C/C+程序器会使用“delete”运算符来释放内存)。这是由JVM本身来完成的,而不是程序。JVM通过确保程序的任何部分都不再引用该对象,从而检测到程序已经不再使用该对象。清除不再使用的对象被称为“垃圾回收”,它可以被视为JVM运行间隔期间的一种分离、独立的活动。这些间隔由多种因素决定,其中之一便是要求更多的heap空间。该内存管理策略的影响是一旦决定JVM的垃圾回收应该开始,执行Java字节代码的所有其它线程,无论是解释或编译的形式,在垃圾回收过程期间都必须返回至安全点并停止。如果该过程持续较长的时间,那么它便会给Java程序的性能造成严重影响。由于这个原因,在分析Java程序的性能时,
22、分析垃圾回收的行为总是非常重要。图4显示了单个JVM在一台8CPU的计算机上执行的过程中,垃圾回收活动发生时的瞬间影响。可以看到,只有一个CPU正在执行有用的工作,即垃圾回收器本身。其它的CPU几乎未被使用。Glance屏幕 垃圾回收的影响图4:在运行HP-UX的8CPU系统上,Glance/gpm工具的CPU屏幕中看到的垃圾回收因此过多的垃圾回收活动是造成Java程序缓慢的重要原因,所以必须通过评估和更改影响heap的JVM选项来进行调整,选项包括-Xms、-Xmx、-Xmn和XX:SurvivorRatio。但是,第一步是检查JVM的垃圾回收部分是否发生了过多的活动。在Glance/gpm
23、的主窗口中我们可以获得很好的线索,来判断垃圾回收活动是否频繁。如下图5所示“尖峰”状的CPU行为类型能够表明出现了我们不希望的垃圾回收活动。图5表明用户程序时间在垃圾回收器接管CPU后经历了非常大的下跌。Glance 频繁的垃圾回收图5:HP-UX Glance/gpm工具中“尖峰”状的CPU行为类型由于我们拥有JVM的“-Xverbosegc”选项,这一检测工作可以通过HP-UX上的Java轻松实现,该选项的使用方式如下。 $ java Xverbosegc:file=myfile.out ClassName表6. 利用-Xverbosegc运行Java这使JVM能够在文件“myfile.o
24、ut”(文件名仅仅是这里的举例)中生成详细的垃圾回收器数据。注:该选项在运行时对JVM只有非常低的影响(除了向磁盘写入输出数据造成的影响),所以必要时可以在生产应用上使用。输出数据(在上例所说的“myfile.out”文件中)很难读懂,因为其原始格式如下: 表7. JVM“Xverbosegc”选项的输出结果该输出文件中有19列数据,描述了垃圾回收器heap消耗期间的各个时间和区域。针对该输出文件,推荐下载HPjtune GUI工具(/go/java)或者从性能调节网站下载“processVerboseGC.awk”文件,地址: HYPERLINK /dspp/tech/tech_TechDo
25、cumentDetailPage_IDX/1,1701,1602,00.html /dspp/tech/tech_TechDocumentDetailPage_IDX/1,1701,1602,00.html并应用如下的命令: $ cat myfile.out |awk f processVerboseGC.awk output.txt表8. 在包含Xverbosegc输出的文件上运行processVerboseGC.awk脚本该命令能够生成非常用户友好的输出文件,示例如下表9所示: GC: Full GC required - reason: Old generation expanded o
26、n last scavengeGC: Full 1.985317 s since last: 1.985317 s gc time: 96 ms eden: 1834928-0/3670016 survivor: 120576-0/262144 tenure:2 old: 3204992-2356088/3928064GC: Scav 2.190710 s since last: 0.205393 s gc time: 4 ms eden: 3669968-0/3670016 survivor: 0-120720/262144 tenure:32 old: 2356088-2356088/39
27、28064表9. 在Xverbosegc输出文件上运行processVerboseGC122.awk脚本后的输出结果在免费下载的HPjtune工具中查看GC数据能够获得对垃圾回收器行为的图形化视图。这是该情形下推荐使用的方法。以上数据描述了程序执行过程中按顺序连续发生的3次垃圾回收事件。每次事件发生的时间,从程序开始时间算起,以秒为单位显示在“Full”或“Scav”之后。即使在了解“eden”、“survivor”、“tenure”和“old”等术语的含义(将会在下文中解释)之前,我们也能够从以上数据中获得许多信息。首先,1次“Full”垃圾回收(GC)事件所占用的时间要比“Scavenge
28、”或“Scav”垃圾回收更多。如果我们看到很多的“Full GC”条目,例如每分钟一次甚至更多,那么我们便需要采取一些措施。如果在数据中看到一个条目包含以下内容:“Full GC required reason : call to System.gc() or Runtime.gc()”那么我们便知道是用户的Java代码或应用使用的一些库或基础设施代码正在显式调用垃圾回收器。这种情况永远都不应该发生。要解决该问题,我们可以将“call to System.gc() or Runtime.gc()”从代码中移除,或者使用JVM选项XX:+DisableExplicitGC来禁止它,如下所示:$
29、java XX:+DisableExplicitGC ClassName表10. 通过禁止显式调用垃圾回收器的选项运行Java第二,我们在“Full”或“Scav”字符串之后便可以看到从程序启动开始计算的时间。该时间(以秒为单位)累计程序运行的时间,使我们能够了解到事件发生时程序执行的进度。“since last”字符串之后是与上一次GC活动相隔的时间。“gc time”字符串表明了该特定的GC事件完成所用的时间。我们应特别注意这些最后的数字。一般来说,正常JVM执行Full GC的次数要少于Scavenge GC。Scavenge GC之间的间隔应该在5秒左右或更长,并且完成的时间不应超过3
30、00-400毫秒。如果Scavenge GC完成的时间达到1分钟甚至更长,那么我们便知道程序暂停了那些执行Java字节代码的线程至少1分钟,出现了性能问题。我们应该考虑调整控制heap内存使用的JVM选项来解决该问题。这可以通过更改与JVM选项Xms、-Xmx和Xmn相关的值来实现,如下所述。一旦了解到heap内存的哪些区域正被过度使用或未被充分利用,那么我们便可以更改这些值。这将会在下一章中讨论。Full GC可能需要1分钟甚至更长的时间,取决于需要执行回收的heap空间的大小。一般来说,好的实践是对JVM运行进行配置,使Full GC能够在1分钟甚至更短的时间内完成,并且相对于Scaven
31、ge GC发生的次数更少。每5至10分钟发生一次Full GC,每次持续10秒或更少,以及每隔5-10秒发生一次较小、持续时间很短(300-400毫秒或更少)的Scavenge Gcevery,表明JVM运行比较正常。heap内存中空间本章节对heap管理进行一定的深入分析。通过了解new和old的对象在JVM整个heap内存中的存放,我们便可以看到该空间被使用的情况。然后我们便可以借助JVM选项Xms、-Xmx和-Xmn来采取措施,从而影响行为的改变。下图6是JVM中整个heap内存的布局图。垃圾回收Heap布局图6:用于Java对象的heap内存结构在图6中我们可以看到在整个heap内存中
32、共有4个“空间”,有时也称“区域”。垃圾回收这一“分代”类型设计的目的是,寿命较短的对象可以在所有时间内一直停留在“New区域”中,并使用一种快速的算法实现回收。寿命较长的对象必须寻找合适的方式进入“Old区域”并保留在那里,直到一种较慢的垃圾回收算法找到它,如果它已经不再使用,那么便可能被清除掉。在上图6中我们没有画出heap内存中的“Permanent区域”空间,本文不对其进行讨论。我在这里提到它,以表示完整性。heap内存中的“Permanent区域”空间被用于存放永久存在的对象以及其它对象。在Java SDK 1.3.1中其默认值是64MB。这一默认的最大值,加上默认的新和旧区域的最大
33、值(分别为16和64Mb)便构成了整个heap默认的128MB最大值,前文中已经提到。Scavenge GC在“New区域”中完成,因此速度更快。Full GC同时包含了“New”和“Old”的区域,因此速度比Scavenges要慢。“New”区域的默认起始大小是2MB。“New”区域的默认最大值是16MB。“Old”区域的默认起始大小是4MB。“Old”区域的默认最大值是48MB,如上图中的阴影区域所示。这些大小可以使用下面的选项进行更改:Xms(heap起始大小)-Xmx(最大heap大小)Xmn(New区域的大小)-XX:SurvivorRatio=(Eden区域的大小除以“from”或
34、“to”区域的大小,后两个区域大小相等)JVM选项。以上前3个选项中每一个后面都可以跟一个数字,表示分配的MB数。例如,Xmn256m表示为New区域分配256MB的空间。建议将Xmn的值设为Xmx值的三分之一。在临时对象使用严重的应用中,也可以将Xmn的值设为Xmx值的一半。-Xmn的值需要根据具体应用进行适当的调节。“New”区域中的“Eden”子空间是新的对象初次创建时用于存放的内存空间。这是一个非常重要的空间,因为所有用户定义的对象都会在程序运行过程中的某个时刻出现 可能持续较长或较短的时间。以下是一个Java程序创建Panel类(一个通用的用户接口类)的一个新对象的实例。这一新的对象
35、会在“Eden”子空间内存放一段时间,如果它在程序中使用很长时间,此后将被拷贝到其它地方,也许是“Old”区域。 Panel p = new Panel();表10. 创建Panel类的一个新对象很自然,Eden空间随着时间会被填满,因为有越来越多的新对象被存放到其中。在Eden区域被填满时,一个Scavenge GC便会启动,并将那些当前存在引用的对象从Eden区域拷贝到“to”区域中。“to”空间是两个“survivor”空间之一,可用于保留一段时间正在使用中的对象,延迟它们进入“旧”的区域,直到它们“经历”多次GC事件。另一个“survivor”空间称为“from”空间。此时,没有引用的
36、对象将会被从Eden区域中清除,从而释放出它们此前所占用的空间。这些便是被垃圾回收的对象。前一次GC事件中可能在“from”子空间内处于等待状态的所有对象也会被拷贝到“to”区域,然后这两个空间交换名称 “from”成为“to”,“to”成为“from”。对象被从“from”和“to”区域之间来回拷贝,直到到达一定的拷贝限制,该限制由“MaxTenuringThreshold”变量设定,如上图,其默认值为32。这意味着对象在“新”的区域中最多可以“经历”32次Scavenge GC和32次from-to交换名称活动,直到最终被“永久化/tenured”并被存放到“Old”区域中。Old区域旨在
37、用于存放程序运行期间一直存在的对象。现在我们便能够较为轻松地理解Xverbosegc的输出结果了。以上表8中包含如下内容的条目:eden: 1834928-0/3670016表11. processVerboseGC122.awk输出结果中的Eden大小数字表明了该GC事件发生之前Eden子空间被占用的大小(箭头前的数字),该事件后Eden空间被占用的大小(箭头后的数字)以及整个Eden空间大小(“/”标记后的数字)。该条目的含义如下:该GC活动之前新对象占用了1834928字节的Eden空间。作为该GC操作的一部分,这些对象被完全从Eden中移除(被存放到其它地方),因为GC之后的Eden占
38、用为零(箭头后的数字)。GC完成之后Eden空间的总大小为3670016字节。相同的读取方式也可以应用到“survivor”和“Old”空间上。在这种情况下,术语“survivor”指名为“from”和“to”的两个子空间的和。每次Scavenge GC时清理Eden子空间是垃圾回收的一种正常行为。但是,如果我们看到每次Scavenge GC之后“Survivor”的数字(“from”和“to”)降到零,那么我们便知道某个地方出现了问题。对象没有足够多地在“from”和“to”子空间之间来回拷贝。相反,它们以超出正常的速度被存放到了“旧”区域中。这一操作可能会导致“旧”区域最终被充满并非长时间
39、存在的对象。这一症状称为“溢出”,如果发现连续的GC事件中MaxTenuringThreshold的值都非常低(2-10),便可以确定是这种症状。如果我们发现“New”区域中没有足够的空间来使对象在其中保留合适的时间,那么我们可以首先使用-Xmn工具来调整“新”区域的大小。这将会扩大所有“新”区域子空间的大小,包括“eden”、“from”和“to”。使用方式如下: $ java Xmn160m Xmx480m Xms480m ClassName表12. 使用Xmn、-Xmx和Xms选项运行Java,分别指定“新”区域、最大总heap值和初始heap值的大小建议“New”区域的大小与整个hea
40、p最大值的比率在1:3到1:2范围之间,后一数字被认为是非常激进的调整。我们也可以使用JVM选项XX:SurvivorRatio=来调节“from”和“to”子空间相对于Eden空间大小的比率,如下所示:$ java Xmn120m Xmx480m Xms480m XX:SurvivorRatio=8 ClassName表13.借助-Xverbosegc选项运行Java这会使Eden子空间的大小为“from”或“to”空间的8倍(后两者的大小相等)。上一实例中的“新”区域将被分成一个96MB的Eden子空间(即12MB的8倍)以及“from”和“to”两个大小均为12MB的子空间,总空间为12
41、0MB。建议XX:SurvivorRatio选项保留其默认值,在JDK 1.3.1中为8。即“Eden”的大小是“from”或“to”子空间的8倍。我们还建议采取以上的操作,目的是减少FullGC的数量并保持MaxTenuringThreshold的值尽可能接近32。MaxTenuringThreshold的值会随着垃圾回收器的执行而调整,所以在程序运行过程中可能会不同。该值越低,对象便会越容易被从“from”或“to”子空间拷贝到“Old”区域中。这是我们希望避免的一种情形。因为JVM的Xverbosegc选项在较长的时间内会生成非常多的数据,所以另一个技巧是将基本的Xverbosegc输出
42、数据导入到电子表格中(如MS Excel)并画出程序运行时间内“新”或“旧”区域增长率的图形。该技巧在开发人员解决方案合作伙伴门户(DSPP)站点上有详细的记录,地址: HYPERLINK /dspp /dspp线程、锁定与争夺Java是一种编程语言,它允许在程序中轻松地创建线程或异步的过程。但是这可能会给对多线程程序不熟悉的程序员带来麻烦。无限制地创建线程当然是不好的实践,应该尽量避免。许多应用服务器中间件系统依赖于创建数千个线程。HP-UX支持在一个进程中拥有许多线程。线程的数量取决于HP-UX内核参数“max_thread_proc”的值。该值可以通过执行“kmtune”命令来查看,如表
43、14所示。$ kmtune |grep max_thread_proc表14.使用HP-UX kmtune命令查看内核可调参数的值幸运的是,我们有多种工具可以在程序执行期间或执行结束后来查看程序的线程行为。这些工具包括Glance/gpm、Hpjmeter和被称为“kill 3”的方法。下面的内容将对它们详细进行介绍。图7显示了用户通过Glance/gpm查看特定Java进程(也许在一系列Java进程中)并检查Java程序运行中创建的所有线程时的数据图形。下图最左边一列中的TID表示每个线程的TID或唯一的线程ID。应该指出的是JVM本身在启动时需要11个线程,它们与用户程序代码所需的线程是分
44、开的。图7:在Glance/gpm中通过进程界面查看正在运行的Java程序的所有线程Java程序员在使用线程时面临的风险包括:创建了太多的线程,超出了操作系统的限制。Java程序中会出现“OutOfMemoryException”的错误信息,或者一个提示线程过多的消息。这个问题非常容易解决。主要方法是在系统上使用Hpjconfig工具来查看内核参数“max_thread_proc”的值,并使用SAM(系统管理)工具进行修改。Hpjconfig工具可以从HP Java网站免费下载。 HYPERLINK /java /java一个线程可能长时间占用访问共享资源的锁,从而导致一些或所有其它的线程不能
45、访问CPU。图8显示了一个线程占用了其它线程需要访问的资源时的问题情形。锁争夺是一种测量方式,用于测量多少线程试图获得该锁以及尝试获取的频率。在争夺很高时,线程需要花时间等待进入对象监视器而不是执行有用的工作。HP-UX版本Java SDK 1.3.1(或以后版本)中的-Xeprof选项为用户提供了关于锁争夺的准确数据,并且该数据可以被Hpjmeter解释。图8:控制多个线程访问资源的操作系统监视器结构线程T1占用了另一线程T2需要访问的资源A的锁。线程T2占用了T1需要访问的资源B的锁。这两个线程进入“死锁”状态,除非一个线程让步,否则程序将不能继续执行。这些问题都与应用软件的设计相关。因此
46、,通过修改软件的结构(涉及重新编译)基本上便可以解决这类问题了。但是,工程师必须使用能够发现这些问题的工具,并通过它们快速发现问题的原因。我们能够获得的有关线程和锁争夺问题的第一个线索来自Glance/gpm的输出。在图9显示的系统图形中,过多的CPU时间被消耗在“系统”时间(较深颜色)而不是“用户”时间(颜色较浅的区域)上。正常系统中的情形应该相反。“用户”时间应该是CPU花费的大部分时间,因为这一时间用于执行应用代码。图9: Glance/gpm中看到的系统时间使用超出正常的证据这是可能出现了线程和锁定问题的一个迹象。然后我们再次使用Glance/gpm来查看系统上各个独立JVM进程所使用
47、的单个系统调用。我们可以获得关于出现锁争夺问题的单个进程的图像,它可能与下图相似。这里,特定HP-UX操作系统调用(如“sched_yield”、“ksleep”和“kwakeup”)被调用的次数非常高,超出了Glance/gpm“累计系统调用计数”一列中测量的所有其它调用。这些调用可能因JVM版本的不同而有所差异,但是性能工程师必须在最高被调用列表中查找所有的调用。图10中指向“send”和“recv”调用的系统调用率的箭头表明这些调用的频率远远低于“sched_yield”和“ksleep”调用。而“send”和“recv”的调用频率应该更高,因为它们在该基于网络的程序中需要完成主要的工作
48、。如果我们解决了这里明显的线程争夺问题(例如,通过围绕轮询(polling)线程和线程池模式重新组织线程设计),我们将会看到非常高的“send”和“recv”调用率。图10:单个进程对特定系统调用非常高的系统调用率 可能出现了线程争夺如果设计中每个对网络流量开放的接口都使用一个线程,那么这种情形的问题便会出现。在同时建立上百或上千个网络连接的情况下,这可能会导致在线程争夺上耗费非常高的系统开销。这类问题在过去的设计中已通过实施HP Poll API得到解决。HP Poll API是设计应用的一种方法,以使用较少的线程。该主题不在本文的讨论范围之内。在Java SDK 1.4中也有一个子系统可用
49、于对异步I/O环境中的线程进行更好的控制。使用KILL 3获得线程数据转储该方法在分析JVM线程时十分简单,但是非常强大。在一个正在运行的JVM进程上使用“kill”命令和参数“-3”或“-s SIGQUIT”不会影响正在运行的JVM,只是使它生成一个关于其当时所保留线程的所有信息的详细转储。使用Glance/gpm,或者简单的“ps ef|grep Java”命令来获得我们想要查看的JVM的进程ID。然后下表15中所示的命令将会通过该程序的标准输出通道生成有关线程数据的全部转储。# kill 3 3493 (if 3493 were the PID of the running JVM)表1
50、5. 在JVM上使用kill 3命令使其进行线程转储在开始调用JVM时,我们还可以将标准输出重新定向到一个文件中。以上的kill命令可能需要用户具有超级用户权限。正在运行的JVM生成的标准输出数据(如果超过一定的大小,可能会被要求重新定向到一个文件),可能与下面的示例相似。图11:在由指定的运行中的JVM进程上执行“kill 3 ”命令时的部分输出数据图11显示了一个特定的线程(其轻量进程ID,图中lwp_id,为14165)正处于挂起状态,因为它一直在等待锁以访问一个特定的对象(由其十六进制地址指定)。这只是一个较大数据转储的一个较小的快照,但能够使读者了解到这一输出。在该输出中我们需要特别
51、注意的是,一个线程长时间占用访问一个对象的锁,而该对象需要被其它线程访问。这导致整个JVM的速度变慢,从而出现问题。我们可以在问题程序运行过程中多次重复“kill 3 ”操作,以检查是否是持续的锁定造成了该问题。但是,在处理拥有大量线程的程序时,这可能会生成非常多的数据。彻底分析所有这些数据并从中找出问题非常困难。作为一个附加的好处,我们可以使用Hpjmeter工具来帮助完成一部分工作。使用hpjmeter工具来检测线程锁定问题分析JVM线程行为的一个更简单的方法是采用HP特定选项Xeprof运行该程序至结束,然后使用Hpjmeter工具分析其输出结果。如果正在JVM中执行的程序能够被完全地终
52、止(即,使用System.exit()或一些适当的关闭过程),那么JVM必须采用如下扩展的分析选项(-Xeprof)来运行。$ java Xeprof:file=myfile.eprof ClassName表16.使用Xeprof选项来运行Java程序,以便在运行中进行监视我们分析生成到文件(例如f)中输出结果的工具是Hpjmeter分析工具,它可以通过以下地址免费下载 HYPERLINK 该工具本身以Java语言编写,因此它可以在任何支持JVM的平台上运行。该工具将读取标准JVM选项Xprof生成的输出文件。但是,如果读取HP JVM特定Xeprof选项生成的输出文件,那么该工具将能够带来更
53、多优势和详细信息。运行Hpjmeter工具(在HP-UX或任何支持Java的平台上)的命令如下表17所示。$ java cp /opt/hpjmeter/HPjmeter.jar HPjmeter表17. 运行Hpjconfig工具该免费的工具除了与线程运行时间相关的测量方法以外,还拥有许多有用的测量方法。这些测量方法在下载站点的指南中有详细的介绍。在本文的该部分中我们仅侧重于使用其进行线程分析。Hpjmeter工具生成JVM运行中关于线程状态及其运行时间的图形页面。我们将Xeprof选项生成的文件载入到工具中,然后选择名为“Metric”的菜单项显示线程柱形图,便可以得到以下的图形。表12.
54、在Hpjmeter工具中显示线程运行时间及其状态的页面信息这使我们能够一次看到所有线程的运行时间,并可以通过双击代表线程的彩色条集中于有问题的某个线程或多个线程,从而进行深入的分析。以上图中的线程0有77.1%的时间在CPU内执行;这是正常的标志。该线程有大约21.4%的报告时间被用于profiler系统开销,只有非常少的时间被用在等待执行或锁争夺上。使用HP的Java SDK 1.3.1+和HPjmeter 1.2+,我们可以获得关于线程争夺问题的非常准确的图形,这些问题可能会降低Java程序的运行速度。除了线程分析以外,Hpjmeter在分析许多其它情况时也非常有用。使用该工具提供的一些测
55、量方法还可以追踪消耗大量CPU和wall时钟时间的方法(method)。这将会在以后的“昂贵的方法调用”一章中详细讨论。线程总结Java程序线程被Java虚拟机映射到操作系统线程,也称HP-UX轻量进程(LWP)。HP-UX中调度单元为单个的线程。每一个线程在Glance工具中都是可见的,例如拥有唯一的LWP编号(LWP ID),使用“Thread List”特性。最初,每个线程优先级的初始值与操作系统中的所有用户进程相同。由于线程在CPU中执行,在正常条件下,其优先级会随着其获得更多的CPU时间而降低。这导致线程在离开CPU时优先级变低。因此操作系统在下一次根据优先级来调度线程时,该线程相对
56、于其它线程可能会处于不利的地位。如果一个特定的Java进程是一台计算机上唯一最重要的用户进程,那么该进程可以通过超级用户干预,在开始或执行过程中被授予最高的调度优先级。这可以分别使用“nice”或“renice”命令来完成,或使用Glance/gpm的“renice”功能。“nice”命令如下表18中所示。# nice -20 java ClassName (notice there are 2 minus signs)表18. 使用“nice”命令运行Java程序“renice”命令需根据正在运行的Java程序的进程ID来执行,进程ID可以使用“ps ef”命令或者在Glance/gpm中使
57、用进程列表页面获得。下表19中使用的示例Java进程ID为1234。# renice 20 1234 (notice there is 1 minus sign)表19. 在运行中的Java程序上运行“renice”命令nice和renice这两个命令在执行时都必须非常谨慎。它们只有在以超级用户身份登录到计算机时才能被执行。这些命令可以改变被调整(reniced)进程中所有线程的优先级。执行以上此类命令的结果是相同计算机上的其它进程与“reniced”的进程相比将处于不利的地位,可能会比不使用该命令时获得更少的CPU时间。但是,在有些情况下这种折衷是值得的。昂贵的方法调用在Java程序中经常会
58、出现这样的情况,少量的程序方法(method)占用了大部分该程序所消耗的时间或资源。很显然,这些是应用设计时需要调整的主要领域。一些方法(method)可能无需修改应用设计或源代码便可完成调整。第一步是发现这些方法的编号和性能特征。Hpjmeter工具最合适于进行这种分析。Hpjmeter具有独特的优势,它可以免费在所有支持Java的环境中运行。第二,JVM的Xeprof选项可生成供Hpjmeter分析的数据,并且经过特别设计,针对其分析的程序只有最低的入侵影响。调用Hpjmeter的方法如以上表17中所示。图13显示了Hpjmeter中关于方法调用次数最多的输出。图13.Hpjmeter工具
59、所见的最高Java程序方法调用计数很明显,在图13中Mark.SimSearch.bel()方法在该程序所有被调用的方法中被调用的次数最多。“bel()”方法调用的次数远远超过的所有其它方法的调用。我们可以使用其它的Hpjmeter测量方法,例如“Exclusive CPU Method Time”来详细分析该方法,以检查它是否占用了大量的程序资源,例如CPU周期或其它方面。然后我们对该方法的设计及其在程序中的使用进行一些修改,从而清除该瓶颈。在一些情况下,特别是与Java程序中格式化日期类的对象相关时,我们无需修改源代码本身便可以实现对频繁调用的方法的修改。当Java程序中格式化日期对象使用
60、非常频繁时,方法“currentTimeMillis”或“getTimeOfDay”便可能会出现在Hpjmeter方法调用计数测量输出图形的顶端。在使用JDBC向数据库写入记录或从数据库中读取记录时,日期对象的使用可能会非常频繁。假设我们已经确定这对程序的性能存在非常严重的负面影响,我们可以使用表20中所示的选项来解决该问题。该选项能够减轻程序执行过程中JVM所使用的日期/时间函数(操作系统中的微小运算)的影响。$ java XX:-UseHighResolutionTimer ClassName表20. 利用该选项运行Java程序,以减轻计时/日期方法的影响内存溢出Java开发世界中最受关注
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2.1《人的社会化》课 件 2026-2027统编版道德与法治八年级上册
- 2026年化工装置开停车安全培训考试试卷
- 微型电机马达项目可行性研究报告
- 2026未来艺术趋势考核试卷
- 建筑施工项目策划方案
- 后浇带施工专项技术方案
- 河流防洪治理工程投标书
- 化工企业危化品储存安全风险控制优化
- 矿山植被重建方案
- 建筑幕墙高空作业方案
- 2026年云南省昆明市重点学校初一入学数学分班考试试题及答案
- 医院门诊检验标本采集工作手册
- 西师大版小学二年级上册数学全册教学设计
- (正式版)DB31∕T 405-2021 《集中空调通风系统卫生管理规范》
- 建筑施工安全与消防管理试题
- 2026内控风险岗面试题及答案
- 内蒙古荣达可再生能源发展有限公司建设25kt-a脱硫副产物硫膏、硫渣提纯工业硫磺综合利用项目水土保持报告表
- 病历书写基本规范解读
- 仓库工程质量控制要点
- 2026中国医药批发企业供应链金融创新模式研究报告
- 2026年危化品从业人员安全考试题库及答案
评论
0/150
提交评论