巧解IBM JVM for Linux onPOWER性能调优

keeper 2010-09-27

你对IBMJVM for Linux onPOWER的性能调优技巧是否了解,这里和大家重点讨论一下用于iSeries和pSeries上的IBMJVMforLinux的一些重要性能调优问题,相信本文介绍一定会让你有所收获。

IBM JVM for Linux onPOWER的性能调优技巧

本文将介绍用于iSeries和pSeries上的IBMJVMforLinux的一些重要性能调优问题。在撰写这篇文章的时候,IBM推出了JDK1.3.132-bit和JDK1.4.2,但无论是32位还是64位风格的,都适用于IBMiSeries和pSeries上的Linux。本文中提供的技巧可应用于IBMiSeries和pSeries上的IBMJDK1.3.1和JDK1.4.2forLinux,但是本文的特别针对目标是最新的IBMJDK版本JDK1.4.2。

编写性能高效的Java代码

本文将重点参考针对JDK1.3.1和JDK1.4.2的 IBMJVMDiagnosticsGuides。

这一节将介绍编写性能高效Java代码的一些通用准则,明确讨论如何避免对象创建和垃圾收集(GC),同时还将讨论JNI、同步和数据结构。

避免对象创建和GC

只要有可能,应该避免创建对象,防止调用构造函数带来的相关性能成本,以及在对象结束其生命周期时进行垃圾收集所带来的成本。

考虑以下这些准则:

只要有可能,就使用基本变量类型,而不使用对象类型。例如,使用int,而不使用Integer。

缓存那些频繁使用的寿命短的对象,避免一遍又一遍地重复重建相同的对象,并因此进行GC。

在处理字符串时,使用StringBuffer而不使用字符串连接,因为字符串对象具有不可变的特性,并且需要创建额外的字符串对象,而这些对象最终必须经历GC。

避免过度对Java控制台进行写操作,降低字符串对象处理、文本格式化和输出带来的成本。

实现数据库连接池,重用连接对象,而不是重复地打开和关闭连接。

使用线程池(threadpooling)。避免不停地创建和删除线程对象,特别是在大量使用线程的时候。

通过System.gc()调用避免在代码中调用GC。GC是一个“停止所有处理(stoptheworld)”的事件,它意味着除了GC线程自身外,其他所有执行线程都将处于挂起状态。如果必须调用GC,那么可以在非紧急阶段或空闲阶段实现它。

避免在循环内分配对象,这会使对象在Java堆上的存活时间超过必要的存活时间。

Java Native Interface

使用本机代码编写应用程序部分,特别是频繁使用的部分,并将之与Java链接,这样做通常是为了提高性能。不过,JVM与本机代码之间的通信通常很慢,因此,太多的JNI调用可能会降低性能。只要有可能就应该将本机操作集合在一起,以减少JNI调用的数量。

使用JNI代码本地处理异常,尽管有时不可避免地会导致性能下降。在这种情况下,应该使用ExceptionCheck()函数,因为与ExceptionOccurred()相比较,它带来的计算开销更少一些。后者必须创建一个将引用的对象,以及一个本地引用。

同步

为了减少JVM和操作系统中的争用,应该只在可行的情况下才使用同步方法。不要将同步方法放到循环结构中。

数据结构

作为一条通用规则,在更简单的数据结构能满足需要的地方,应该避免使用更复杂的数据结构。例如,在可以使用数组的地方不要使用向量。使用最有效的方法搜索元素,并将元素插入数据结构中,比如说,在向量的结尾处添加和删除元素,以便获得更好的性能。

提高性能的编译选项

用-O优化标记编译Java代码。代码优化提供了以下几个好处:

让代码变得模糊,使它更难以进行“逆向工程(reverse-engineer)”。

极大地增强源代码的安全性。

极大地减小Java程序的大小。

提高运行时性能

提高性能的环境设置

◆Spinloop

目前,通过调整SPINLOOP变量和时间片值,可以显示可获得的最大性能。IBM_LINUX_SPIINLOOP时间值是一个进程在锁定之前可以在某个繁忙的锁上自旋的次数。有三个SPINLOOP变量可进行调整(从0到100的数字):

IBM_LINUX_SPINLOOP1

IBM_LINUX_SPINLOOP2

IBM_LINUX_SPINLOOP3

在16路LPAR上执行的基准测试认为以下设置将是最佳设置:

IBM_LINUX_SPINLOOP1=96

IBM_LINUX_SPINLOOP2=85

IBM_LINUX_SPINLOOP3=85

与其他任何全局变量一样,需要在shell实例中设置这些变量,JVM进程将会在这个实例中运行,因此,可以通过JVM将这些设置读取到全局变量表中。

◆Sysctl

在可以运行内核2.4.19的SLES8上,有一个用于设置Linux内核中时间片的最大值和最小值的选项。这些都是通过sysctl命令设置的。为了获得好的Java性能,极力推荐将sysctl值sched_yield_scale设置为1。

路径
CLASSPATH变量应该在搜索路径的前面包含一些最常使用的Java库。对于LIBPATHandLD_LIBRARY_PATH变量,也应该这样做,以便获得最常使用的JNI共享库。

用户限制设置

为了获得最佳性能,让运行JVM进程的用户拥有经过正确配置的用户设置是很重要的。这些参数可以设置成以下两种形式之一:

暂时地,适用于通过ulimit命令登录shell会话期间。

永久地,通过将一个相应的ulimit语句添加到由登录shell读取的文件之一(例如~/.profile),即特定于shell的用户资源文件;或者通过编辑/etc/security/limits.conf。

建议设置成无限制(unlimited)的一些重要设置是:

数据段长度:ulimit–dunlimited

最大内存大小:ulimit–munlimited

堆栈大小:ulimit–sunlimited

CPU时间:ulimit–tunlimited

虚拟内存:ulimit–vunlimited

对于需要做许多套接字连接并使它们处于打开状态的Java应用程序而言,最好通过使用ulimit–n,或者通过设置/etc/security/limits.conf中的nofile参数,为用户把文件描述符的数量设置得比默认值高一些。

GC和Java堆

“垃圾收集器”是影响JVM性能的最重要的JVM组件之一。关于GC和堆大小调优的一般性IBMJVM讨论(在针对JDK1.3.1和JDK1.4.2的IBMJVMDiagnosticsGuides中)也可应用于IBMJVMonLinux(包括LinuxonPOWER),只是有一些IBMJVMonLinux特定的东西,后面会进行讨论。

最大堆大小是由–Xmx控制的,在32位IBMJVMforLinux上,可以将该值设置得比在32位IBMJVMforAIX上的更高一些,因为这两个操作系统的内存模式有所不同。如果没有指定–Xmx选项,则使用默认设置(即实际内存的一半,最小值是16MB,最大值是512MB)。

如果没用–Xms选项明确指定初始堆大小,那么该值是默认值4MB。有关GC和Java堆调优的更多信息,请参阅针对JDK1.3.1和JDK1.4.2的IBMJVMDiagnosticsGuides中的“DebuggingPerformanceProblems:JVMPerformance”。“UnderstandingtheGarbageCollector”和“GarbageCollectorDiagnostics”这两章也值得一看。

JIT

就性能而言,JIT是最重要的JVM组件。关于IBMJVMJIT的一般性讨论,请参阅JVMDiagnosticsGuide中的“UnderstandingtheJIT”小节。要获得关于JIT性能的Linux特定细节,请参阅“LinuxProblemDetermination”和“JITDiagnostics”的JIT部分。

监控JVM

在JVMDiagnosticsGuide的“LinuxProblemDetermination”一章中,详细地讨论了IBMJVMforLinux性能问题确定、JVM监控和一些工具。

以下章节可能有其他的价值:

追踪Java应用程序和JVM。

使用JVM监控接口(JVMMI)。

使用可靠、可用和可服务的接口。

使用JVMPI。

使用第三方工具。

Linux线程模型和JVM

以下是一些线程模型实现方面的详细说明,该实现将影响不同Linux发行版本上的JVM性能。请参阅JVMDiagnosticsGuide中的“LinuxProblemDetermination”一章,以了解更多细节。

另一个要知道的问题是Linux上的线程浮点堆栈限制,正如JVMDiagnosticsGuide的“FloatingStacksLimitation”小节中所讨论的那样。

相关推荐