文章目录
本章内容:1、性能调优的基础理论和原则;2、调优的一般流程。为了更好掌握本章的内容,你需要熟悉本书第3章介绍的概念,特别是3.3和3.4节。
一、方法
对性能需求的这种分类,称为系统需求。与功能需求不同,系统需求关注应用程序运行的特定方面,譬如存吐量、响应时,间、内存消耗、启动时间、可用性、可管理性,等等;功能需求关注的是应用程序按照什么方式运行,产生什么输出。
1、假设条件
逐步展开的调优过程中,我们假设应用程序的执行遵循下面几个阶段。
- 初始化阶段,应用程序在这个阶段中初始化重要的数据结构及其他必要的组件。
- 稳定态阶段,应用程序在这个阶段消耗了大多数的时间,核心的函数都在这个阶段中执行。
- 总结阶段(可选),总结性的工作在这个阶段进行,例如生成报告等,典型的场景是在应用程序执行停止前,运行基准测试,生成相应的报告。
应用程序在稳定态阶段消耗的执行时间最长,因此也是我们最关注的阶段。
2、测试基础设施需求
简言之,性能测试环境即使不能与生产环境完全一致,也应该尽量模仿生产环境,同时要有能力收集所关注的性能指标,即内存使用情况、延迟、吞吐量以及启动时间。测试环境与生产环境越接近,性能调优的结果越准确,效果也越好。
二、应用程序的系统需求
1、可用性
可用性是对应用程序处于可操作、可使用状态的度量。可用性需求指的是当应用程序的某些组件发生故障或失效时,应用程序或应用程序的一部分在多大程度上还可以继续提供服务。
2、可管理性
可管理性是对由运行、监控应用程序而产生的操作性开销的度量,同时也包含了配置应用程序的难易程度。可管理性需求用于衡量系统管理的难易程度。一般来说,应用程序使用的JVM数量越少,运行、监控应用程序的运营成本越低。与此同时,使用的JVM数目越少,配置也越容易,然而这将会牺牲应用程序的可用性。
3、吞吐量
吞叶量是对单位时间内处理工作量的度量。
4、延迟及响应性
延迟,或者响应性,是对应用程序收到指令开始工作直到完成该工作所消耗时间的度量。
5、内存占用
内存占用指在同等程度的吞吐量、延迟、可用性和可管理性前提下,运行应用程序所需的内存大小。内存占用通常以运行应用程序需要的Java堆大小或者运行应用程序需要的总内存大小来表述。一般情况下,通过增大Java堆的方式增加可用内存能够提高吞吐量、降低延迟或者兼顾二者。应用程序的可用内存减少时,吞吐量和延迟通常都会受到影响。
6、启动时间
启动时间是应用程序初始化所消耗的时间。此外,Java应用程序中另一个值得关注的指标是现代JVM完成应用程序热区( Hot Portion )优化,初始化所消耗的时间。Java应用程序初始化的完成时间取决于很多因素,包括(但不限于):初始化时载入的类的数量、需要初始化的对象的数量、这些对象如何初始化以及HotSpot VM的运行时环境的选择,即Client模式还是Server模式。
三、对系统需求分级
调优过程的第一步是划分应用程序的系统需求优先级,最重要的系统需求左右了刚开始的很多决定。
四、选择JVM部署模式
1、单JVM部署模式
将Java应用部署在单个JVM上时,由于不需要管理多个JVM,可以降低管理成本。但是存在单点故障的问题。
2、多JVM部署模式
将Java应用程序部署到多个JVM实例能够获得更好的可用性,以及更低延迟的可能性。
使用多JVM时,可以将不同JVM绑定到不同的处理器集。
与单JVM部署比较起来,采用多JVM部署Java应用的挑战在于监控、管理以及维护多JVM的代价较大。
3、通用建议
一般情况下,使用的JVM数目越少越好。使用的JVM越少,监控及管理的成本就越低,消耗的总内存也更少。
五、选择JVM运行模式
1、client模式或server模式
- HotSpot VMH有2种JVM运行模式可以选择,分别是:Client模式或Server模式。Client模式的特点是启动快、占用内存少、JIT编译器生成代码的速度也更快。Server模式则提供了更复杂的生成码优化功能,这个功能对于服务器应用而言尤其重要。
- 第3种HotSpot虚拟机运行时被称为Tiered Server模式,它结合了Client和Server运行模式的长处,即快速启动和高效的生成码。通过
-server-xx:TieredCompilation
命令行选项可以启用Tiered Server模式。 - 如果初始时你不知道应该使用哪种运行模式,可以选择Server模式,如果启动时间或内存占用达不到要求,并且你使用的是Java 6 Update 25以上的版本,可以尝试使用Tiered Server运行时。
2、32位/64位JVM
表7-1提供了一些指导原则,帮助大家判断何时使用32位或64位JVM。注意.,64位HotSpot虚拟机中没有提供Client模式(客户端运行时)选项。
3、选择垃圾收集器
进入到调优流程的下一步之前,我们需要选择初始的垃圾收集器。
很多情况下使用Throughput收集器就能达到应用程序的停顿时间要求,所以我们可以从" Throughpur集器入手,需要时再转向使用CMS收集器,即使的确有必要使用CMs收集器,这也只会作为应用程序延迟调优步骤的一部分,发生在调优过程的晚期。关于JVM的调优流程,请参考图7-1。
六、垃圾收集调优基础
这一节会介绍影响垃圾收集性能的三个主要的属性、垃圾收集调优的三个基本原则以及HotSpot VM垃圾收集调优时需要采集的信息。
1、性能属性
- 吞吐量
- 延迟
- 内存占用
2、基本原则
- 每次Minor GC都尽可能多地收集垃圾对象。
- 处理吞吐量和延迟问题时,垃圾处理器能使用的内存越大,即Java堆空间越大,垃圾收集的效果越好,应用程序运行也越流畅。我们称之为"GC内存最大化原则"。
- 在这三个性能属性(吞叶量、延迟、内存占用)中任意选择两个进行JVM垃圾收集器调优。我们称之为"GC调优的3选2原则"。
3、命令行选项及GC日志
-
GC日志是收集调优所需信息的最好途径。这意味着我们需要通过命令行开启HotSpotVM的GC统计信息采集功能。为了定位问题,即便在生产系统上开启GC日志也是个不错的主意。开启GC日志对性能的影响极小,却可以提供丰富的数据。
-
HotSpot VM提供了多个GC日志相关的命令行选项,我们推荐使用下面这些已经精简过的命令行集:
-XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc: <filename>
-XX:+PrintGCTimeStamps
打印从HotSpot VM启动直到GC开始所经历的时间(以秒计时)。-XX:PrintGCDetails
提供垃圾收集器相关的统计数据。-Xloggc: <filename>
选项可以指定将GC的日志信自记录到名为filename的文件中。
GC日志的看法,可详见4.2.2小结。由新生代和Java堆占用的大小,你可以很快推算出老年代占用的空间。例如: Java堆的大小是1006848K,新生代堆占用的空间是306432K,那么老年代堆占用的空间就是1006848K-306432K= 700416K。
垃圾收集之前,老年代占用是296198K-295648K = 550K。
垃圾收集之后,老年代占用的空间是33518K-32968K = 550K。
在这个示例中,垃圾收集前后老年代的大小没有发生变化,意味着这个过程中没有对象从新生代提升到老年代。 -
如果你需要用日历时间格式打印时间戳,可以使用
-XX:PrintGCDatestamps
命令行选项。
虽然输出中含时区,但时间是该时区的本地时间,而不是GMT时间。 -
针对高延迟问题调优HotSpot VM时,下面的这两个命令行选项很有用,通过它们可以获得应用程序由于执行JVM安全点操作而阻塞的时间以及两个安全点操作之间应用程序运行的时间。
-XX:+PrintGCApplicationStoppedTime #执行JVM安全点操作而阻塞的时间 -XX:+PrintGCApplicationConcurrentTime #两个安全点操作之间应用程序运行的时间
由于安全点操作会阻塞Java代码的执行,了解应用程序的延迟与某安全点是否相关非常有帮助。使用命令行选项
-XX:+PrintSafepgintStatistics
可以将垃圾收集的安全点与其他的安全点区分开来。 -
表7-2总结归纳了本节中垃圾收集的命令行选项并提供了使用的建议。