利用标准 Java、JVM 和系统优化
每发布一个新的 JVM 版本都将改善性能和可靠性。对 Java 代码进行优化要比对使用传统语言编写的代码进行优化困难得多,因为大部分 JVM 都可以响应不断变化的条件和配置反馈。但是,您仍然可以使用大量针对 J2EE、Java 技术和 JVM 优化的标准方法来提升应用程序性能。
下面的小节将着重介绍一些常见的优化,可以提供有限的应用程序性能提升。利用标准 J2EE、Java 编码和 JVM 优化可以提供基本的改进,从而提升整个应用程序并实现显著的性能改进。
基准对象分配和对象重用
J2EE 应用程序和 Java 技术的对象分配较慢这一缺点一直都为人诟病。在过去确实如此,然而最新一代的 JVM 在这方面有所改善。但是,研究一下 JVM 在特定环境中的执行情况仍然不失为一个好主意。
分配开销具体取决于可用的资源和特定 JVM 的性能以及 J2EE 实现。最好编写一些简单的基准测试来比较一下在 J2EE/JVM 环境中分配新对象的成本和重用现有对象的成本。除非对现有应用程序执行更新,否则这些信息没有什么用处,但是对于编写新应用程序十分有帮助。
释放内存
内存泄漏导致应用程序的大小随时间不断增长,该问题在 Java 应用程序中尤为突出,因为消耗完堆空间后将触发 JVM 的垃圾收集。使用上文讨论的系统监视工具或性能监视工具监视应用程序的内存使用情况,并检查代码以确保在处理完分配的对象后总是能够释放它们。一些内存泄漏问题常常不易发觉,比如 Hashtable 和 Vector 之类的 Java Collections 类中的内存泄漏,这些类在删除了所有其他引用后仍然会保持对对象的引用。
减少显式垃圾收集的次数
如今的 JVM 在何时需要执行垃圾收集以及收回哪些对象方面表现得十分智能。同时,垃圾收集是一项 JVM 操作,对性能会产生很大的影响。如果需要执行显式的垃圾收集来降低应用程序内存使用,那么尝试在低负载情况下或在非繁忙时刻实现垃圾收集。
优化系统垃圾收集
大多数现代 JVM,比如 IBM Java 版本 5.0 及更高版本,都支持多种垃圾收集策略。检查您的 JVM 所支持的策略,看看使用不同的策略是否会改善吞吐量与垃圾收集引入的暂停之间的平衡关系。
研究 JVM 堆调优
堆调优 控制单独 JVM 和其中运行的应用服务器实例可以使用的内存量。堆调优涉及两个参数:堆的初始大小和最大大小。最大堆大小应当始终小于物理内存 — 当堆开始换入磁盘后,Java 性能将迅速降低。它必须足够低,以在物理内存的范围内包含堆。一条通用规则是将初始堆大小设为最大堆大小的 25%。
最大化系统内存
大多数 UNIX 系统都支持大量内存。Java 应用程序和 JVM 本身都需要使用大量内存。最大化系统内存能够增加 Java 堆的大小,同时仍然确保它小于物理内存。最大化系统内存通常会通过减少内存交换来提升系统系能。
减少运行的进程
将关键系统上运行的进程的数量减到最少应当成为部署流程的一个标准组成部分,但是这一点常常被忽视。尽管在 Linux? 系统上更加常见,但是许多 UNIX 系统都会启动或提供实际上不会在这些系统上使用的服务器进程或服务。常见的、经常被忽视的例子包括 FTP 之类的服务和 getty 进程,后者将等待目前也许永远不会发生的串口登录(serial login)。
检查您的系统以确保没有运行多余的进程,并且终止实际上没有必要运行的任何进程,从而为业务关键型应用程序释放处理器和内存资源。减少运行进程的数量还有另外一个好处,就是通过减少或去除系统访问点来提高安全性。
结束语
优化常常被看作是一种事后行为,就是说在应用程序已经编写完并且可以正常工作之后再执行优化。这种方法通常不太高明。在应用程序设计和实现过程中应用良好的设计决策和最佳实践可以防止许多可能需要优化的编码问题,从而能够对应用程序执行预先优化。
Donald Knuth 曾经指出,“提前优化是万恶之源”。尽管这句话通常是正确的,但是性能分析和优化机会分析应当成为每个应用程序的部署和维护流程的一部分。本文首先讨论了一些可以在创建应用程序之前决定的设计决策,从而获得易于维护、易于测试、可良好执行的应用程序,并提供了挂钩以便在出现问题时简化调试工作。后续的小节讨论了用于在现有应用程序中识别问题根源并加以解决的技术,并着重介绍了标准 J2EE、Java 编码和 JVM 优化方法,这些方法可以提升新应用程序和现有应用程序的性能。