前言

当O'Reilly第一次找我,让我写一本关于Java性能优化的书时,我心存疑虑。我心想:Java性能不是已经没什么好写的了吗?的确,我每天仍然致力于提升Java应用程序(和其他应用程序)的性能,但是我更认为自己大部分时间在优化低效的算法和处理外部系统的瓶颈,而不是解决任何与Java性能优化直接相关的问题。

思考片刻后我确信,我像往常一样欺骗了自己。端到端的系统性能优化的确耗费了我大量的时间,我时不时也会碰到原本可以用1算法却用了算法的代码。然而实际上,我每天仍会考虑垃圾回收(GC)性能与JVM编译器性能,也会思索如何从Java API中获得最佳性能。

1从研究算法的角度来说,log的底数并不重要。因此,这里不标注底数。——编者注

这并不是要抹去20多年来Java和JVM在性能方面的巨大进步。20世纪90年代后期,当我在Sun公司担任Java布道师时,唯一真正可用的“基准测试”工具是Pendragon软件的CaffeineMark 2.0。由于种种原因,该工具的设计很快就限制了其使用价值。然而在那时,我们很喜欢告诉大家,基于这个基准测试,Java 1.1.8的性能比Java 1.0的性能高8倍。这当然是真的,因为Java 1.1.8有了真正的即时编译器,而Java 1.0几乎完全是解释型的。

之后,标准委员会开始制定更严谨的基准测试,Java的性能围绕这些基准测试开始提升。结果,JVM的各个方面都有了长足的进步,包括垃圾回收器、编译器和API。这个过程如今当然还在持续,但一个重要的事实是,性能优化变得越来越难。通过引入即时编译器实现8倍的性能提升,这在工程上很简单。尽管编译器还在持续改进,但我们再也无法实现这样大的提升了。垃圾回收器的并行化也带来了巨大的性能提升,但是这些最近的改进更多是渐进式的。

这是典型的应用程序发展历程(JVM本身也是应用程序):在项目初期,很容易找到架构上的改进点(或代码缺陷),改进后会带来巨大的性能提升。在成熟的应用程序中,很少能找到这样的性能改进点。

在很大程度上,我最初担心的是工程界对于Java性能可能已经没什么可做的了。不过,有几件事让我确信自己错了。首先,我每天都会遇到关于在特定环境中运行JVM的这样或那样的问题。新的工程师源源不断地进入Java领域,JVM的运行机制在某些方面又比较复杂,因此,对其操作给出指导仍有裨益。其次,计算环境的变化似乎也改变了工程师如今面临的性能问题。

在过去的几年里,人们对性能的关注已经分化。一方面,大型机器已经很常见了,其上可运行使用大量堆内存的JVM。JVM已经使用了新的G1垃圾回收器来处理这些内存。作为一种新的技术,G1垃圾回收器比传统垃圾回收器更需要手动优化。另一方面,云计算已经重新证明了小型单CPU机器的重要性:你可以去Oracle、Amazon或者其他公司租用一台便宜的单CPU机器,用来运行小型应用程序服务器。(你并不会得到一台真正的单CPU机器,实际上你得到的是一台非常大的机器上的虚拟OS镜像,但是这个虚拟OS被限制只能使用一个CPU。对于Java应用程序来说,这和运行在单CPU机器上是一样的。)在这些情况下,正确管理少量内存就变得非常重要。

Java平台也在不断进化。每个新的Java版本都会提供新的语言特性和新的API,虽然这并不一定能提升应用程序的性能,但能提高开发人员的生产力。善用这些语言特性有助于使缓慢迟钝的应用程序顺畅运行。平台的进化带来了一个值得注意的性能关注点:在两个程序之间用JSON交换信息,毫无疑问比使用高度优化的专有协议更加简洁和高效。为开发人员节省时间确实可以提升生产力,但是确保在生产力提升的同时性能也提升(至少打平)才是真正的目标。

本书面向希望理解JVM和Java API的各个方面如何影响性能的性能优化工程师和开发人员。

如果你的网站要在周一早晨上线,而你直到周日深夜还在为一个性能问题寻找快速解决方案,那么本书不适合你。

如果你是性能分析新手,刚开始学习分析Java应用程序,那么本书会对你有所帮助。我的目标是提供足够多的信息和背景,让新手工程师能够理解如何将基本的性能优化准则应用到Java应用程序中。然而,系统性能分析是一个广阔的领域,领域内有许多关于系统分析的优秀资源(这些资源当然适用于Java),从这个意义上说,本书很适合成为这些资源的有益补充。

不过从根本上讲,要让Java应用程序跑得快,需要对JVM和Java API的实际工作方式有深入的理解。Java的调优标志数以百计,对JVM进行优化不应该是盲目地试验这些标志,看看哪个有效果。相反,我会提供有关JVM和Java API运行的详尽知识,希望你在理解了这些原理之后,能够通过观察应用程序的具体行为来理解其性能欠佳的原因。了解了这些,摆脱不理想的、低效的Java应用程序行为就变得很简单了,至少比以前简单。

Java性能优化工作的一个有趣的方面是,开发人员的技术背景往往与性能组或QA组的工程师截然不同。我认识一些开发人员,他们可以记住一些不常用的API方法签名,那些方法签名数量庞大又晦涩,但是他们不知道-Xmn标志的含义。我还认识一些测试工程师,他们通过给垃圾回收器设置各种标志来竭力地提升程序性能,却几乎无法写出一个像样的Hello World程序。

Java性能优化包括两个方面:一是编译器和垃圾回收器等的标志优化,二是API的最佳实践。本书假设你对如何编写Java应用程序有很好的理解,即使你的兴趣点不在Java的编程方面,我也会用相当大的篇幅讨论应用程序,包括含有大量数据的示例应用程序。

如果你的主要兴趣是JVM本身的性能优化,即不通过修改代码进行JVM优化,那么本书的大部分内容仍然对你有益。你可以随意跳过编码的部分,只专注于你感兴趣的内容。在这个过程中,也许你会深入了解Java应用程序如何影响JVM性能,并能给开发人员提出建议,从而使你的性能优化工作变得更轻松。

本书第1版出版之后,Java的发布周期改为6个月,同时定期发布长期支持版本。这意味着第2版英文版出版时,Java的版本是Java 8和Java 11。尽管本书第1版介绍了Java 8,但那时它还相当新。第2版专注于更加成熟的Java 8和Java 11,主要的更新内容涉及G1垃圾回收器和Java飞行记录器,也涉及Java在容器化环境中运行方式的变化。

本书第2版会讲解Java平台的新特性,包括新的微基准测试工具(jmh)、新的即时编译器、应用程序类数据共享、新的性能工具,以及Java 11的新特性,比如紧凑字符串和字符串连接的增强。

本书使用如下排版约定。

黑体字

表示新的术语或重点强调的内容。

等宽字体(constant width)

表示程序代码,以及段落中引用的程序元素,比如变量名、函数名、数据库、数据类型、环境变量、语句和关键字。

等宽粗体(constant width bold

表示应该由用户输入的命令或者其他文本。

等宽斜体(constant width italic

表示应该由用户提供的值或者根据上下文确定的值。

该元素表示要点总结。

补充资料(代码示例、练习等)可以在以下地址下载:https://github.com/ScottOaks/JavaPerformanceTuning

本书旨在帮助你完成工作。一般来说,你可以在自己的程序或文档中使用本书提供的示例代码。除非需要复制大量代码,否则无须联系我们获得许可。比如,使用本书中的几个代码片段编写程序无须获得许可,销售或分发O'Reilly图书的示例光盘则需要获得许可;引用本书中的示例代码回答问题无须获得许可,将本书中的大量示例代码放到你的产品文档中则需要获得许可。

我们很希望但并不强制要求你在引用本书内容时加上引用说明。引用说明通常包括书名、作者、出版社和ISBN,比如“Java Performance by Scott Oaks (O'Reilly). Copyright 2020 Scott Oaks, 978-1-492-05611-9”。

如果你觉得自己对示例代码的用法超出了上述许可的范围,欢迎你通过permissions@oreilly.com与我们联系。

40多年来,O'Reilly Media致力于提供技术和商业培训、知识和卓越见解,来帮助众多公司取得成功。

我们拥有独一无二的专家和创新者组成的庞大网络,他们通过图书、文章、会议和我们的在线学习平台分享他们的知识和经验。O'Reilly的在线学习平台让你能够按需访问现场培训课程、深入的学习路径、交互式编程环境,以及O'Reilly和200多家其他出版商提供的大量文本资源和视频资源。有关的更多信息,请访问https://www.oreilly.com

如有与本书有关的评价或问题,请联系出版社。美国:

美国:

O'Reilly Media, Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

中国:

北京市西城区西直门南大街2号成铭大厦C座807室(100035)

奥莱利技术咨询(北京)有限公司

O'Reilly的每一本书都有专属网页,你可以在那儿找到本书的相关信息,包括勘误表、示例代码以及其他信息。

本书的网页是https://oreil.ly/java-performance-2e

对于本书的评论和技术性问题,请发送电子邮件到errata@oreilly.com.cn

要了解更多O'Reilly图书、培训课程和新闻的信息,请访问以下网站:https://www.oreilly.com

我们在Facebook的地址如下:http://facebook.com/oreilly

请关注我们的Twitter动态:http://twitter.com/oreillymedia

我们的YouTube视频地址如下:http://www.youtube.com/oreillymedia

在此,我要感谢每一位在编写本书的过程中帮助过我的人。这本书总结了我过去20多年中,在Sun公司和Oracle公司的性能组和其他工程组工作时所积累的多方面知识。因此,为本书的出版提供过帮助的人相当多。感谢这段时间里与我共事过的所有工程师,特别是过去一年里耐心回答我各种问题的人,谢谢你们!

我要特别感谢Stanley Guan、Azeem Jiva、Kim LiChong、Deep Singh、Martijn Verburg和Edward Yue Shung Wong,感谢他们在审阅初稿时提供的宝贵意见。他们没能找出书中所有的错误,但是我相信书里的内容在他们的努力下得到了极大的改进。Ben Evans、Rod Hilton和Michael Hunger在各个方面提供了帮助,让本书第2版有了很大改善。我在Oracle Hotspot性能组的同事Eric Caspole、Charlie Hunt和Robert Strout也耐心地帮我解决了第2版中的各种问题。

O'Reilly公司的工作人员一如既往地给了我很大帮助。我很荣幸能与Meg Blanchette编辑合作完成第1版,而Amelia Blevins则对第2版进行了全面而细心的指导。感谢你们在此过程中给予我的鼓励!最后,我必须感谢我的伴侣James,感谢他容忍我工作到深夜,容忍我在周末吃晚餐时不断地分心。

扫描下方二维码,即可获取电子书相关信息及读者群通道入口。