一、性能优化的一般概念
人们普遍认为Java程序总是比C程序慢,对于这种意见,大多数人或许已经听得太多了。实际上,情况远比那些陈旧的主张要复杂。许多 Java程序确实很慢,但速度慢不是所有Java程序的固有特征。许多Java程序可以达到C或C++中类似程序的效率,但只有当设计者和程序员在整个开发过程中密切注意性能问题时,这才有可能。
本文的主要目的是讨论如何优化Java IO操作的性能。许多应用把大量的运行时间花在网络或文件IO操作上,设计拙劣的IO代码可能要比经过精心调整的IO代码慢上几倍。
说到Java程序的性能优化,有些概念总是一次又一次地被提起。本文的示例围绕IO应用的优化展开,但基本原则同样适用于其他性能情况。
对于性能优化来说,最重要的原则也许就是:尽早测试,经常测试。不知道性能问题的根源就无法有效地调整性能,许多程序员因为毫无根据地猜测性能问题的所在而徒劳无功。在一个只占程序总运行时间百分之一的模块上花费数天时间,应用性能的改进程度不可能超过百分之一。所以,应当避免猜测,而是采用性能测试工具,比如一些代码分析工具或带有时间信息的日志,找出应用中耗时最多的地方,然后集中精力优化这些程序的热点。性能调整完成后,应当再次进行测试。测试不仅有助于程序员把精力集中在那些最重要的代码上,而且还能够显示出性能调整是否真地取得了成功。
在调整程序性能的过程中,需要测试的数据可能有很多,例如运行总时间、内存占用平均值、内存占用峰值、程序的吞吐能力、请求延迟时间以及对象创建情况等。到底应该关注哪些因素,这与具体的情况和对性能的要求有关。大部分上述数据都可以通过一些优秀的商品化分析工具测试得到,然而,并非一定要有昂贵的代码分析工具才能收集得到有用的性能数据。
本文收集的性能数据只针对运行时间,测试所用的工具类似于下面的Timer类(可以方便地对它进行扩展,使它支持pause()和 restart()之类的操作)。带有时间信息的日志输出语句会影响测试结果,因为这些语句也要创建对象和执行IO操作,Timer允许我们在不用这类语句的情况下收集时间信息。
public class Timer { // 一个简单的“秒表”类,精度为毫秒。 private long startTime, endTime; public void start() { startTime = System.currentTimeMillis(); } public void stop() { endTime = System.currentTimeMillis(); } public long getTime() { return endTime - startTime; } } |
引起Java性能问题的常见原因之一是过多地创建临时对象。虽然新的Java虚拟机在创建许多小型对象时有效地降低了性能影响,但对象创建属于昂贵操作这一事实仍旧没有改变。由于字符串对象不可变的特点,String