JVM调优–理论篇从理论层面介绍了如何对JVM调优。这里再写一篇WIKI,尝试记录下JVM参数使用的最佳实践,注意,这里重点介绍HotSpot VM的调参,其他JVM的调参可以类比,但不可照搬。
Java版本选择
基于Java开发应用时,第一个要考虑的问题,就是Java版本的选择。一般情况下,一个团队或一个组织使用相同的Java版本。由于现在Java版本的发布周期是半年一个版本,所以在实际应用中应选择发行版本,目前支持的发行版本有Java 11、Java 17、Java 21。当然,很大一部分厂商使用Java 8。尽管Java官方目前已不在直接支持Java 8的发行版本,但是Java 8因其广泛且长久的使用,已经非常稳定,且部分有能力的厂商还在维护Java 8,所以Java 8也是一个不错的选择。更多Java版本信息可以参考官网。注意,Java提供的版本均是收费版本,如果需要获取免费版本,可以获取OpenJDK。OpenJDK是Java语言的一个开源实现,OpenJDK采用GPL协议,主要组件包括Hotspot JVM、Java核心类库和javac编译器。OpenJDK具有开源免费、跨平台、高性能和多版本支持等特点,适用于Java应用程序开发、桌面应用程序等多种场景。可以从adoptium网站获取已编译的OpenJDK版本。
JVM类型选择
Java提供了Java Language and Virtual Machine Specifications,约定了JVM的实现细节,这样不同的厂商可以实现自己的JVM。目前,主流的JVM有:HotSpot VM、IBM JVM、Open JDK、GraalVM等。在选用JVM类型时,根据稳定性、高性能、安全性、可维护性、费用等方面组合考虑。如在Java 8中,通常使用Oracle的HotSpot JVM。如果期望使用免费版本,可以选择Open JDK。
JVM部署平台相关选择
JVM部署时,是选择32位JVM,还是64位JVM。HotSpot VM默认的执行位数取决于所安装的JDK版本和操作系统。在32位操作系统上,只能运行32位的JDK,因此HotSpot虚拟机也只能在32位模式下执行。而在64位操作系统上,可以选择安装32位或64位的JDK。如果安装了64位的JDK,那么HotSpot虚拟机将默认在64位模式下执行。推荐在64位操作上安装64位的JDK版本。注意,不同操作系统上,对应的版本不同,所以在选择JVM位数的同时,也要注意选择和待部署操作系统向匹配的版本。此外,针对不同的CPU架构,JVM的版本也不尽相同。在选择JVM执行位数时,还应考虑CPU架构。
JVM部署模式选择
JVM部署模式指的是将应用部署到单个JVM实例上,还是部署多个JVM实例上。目前应用的主流架构是微服务架构。对一个应用来说,常常需要拆分成多个独立的微服务。对于每个微服务来说,为了保证其高可用,通常需要多个实例。所以,对于一个大型的应用来说,是将其拆分成微服务单独部署。而对一个微服务,会对应多个服务实例,且每个每个服务部署在隔离的环境中,如Kubernetes的Pod中。JVM部署模式是架构层面需要考虑的事情,针对一个Java进程来说,无需考虑。
JVM运行模式
为Java应用选择JVM运行模式,就是指定以何种方式运行JVM,可选项有:client模式、server模式和混合模式。注意,混合模式是在Java 7及之后的版本才引入。推荐使用混合模式,这也是Java 8及之后的版本默认的运行模式。该模式可以很好地融合client模式和Server模式的主要特征。如无特殊说明,使用混合模式即可,除非有明确诉求需要使用client模式或server模式。选用server模式启动JVM的示例命令如下:
java -server -jar hello-world.jar
1
上述示例命令中,使用server模式启动了一个hello-world的Java应用。
垃圾收集器选择
JVM的一个重要职责是实现内存的自动化管理。而实现内存的自动化管理的关键就是垃圾收集器。垃圾收集主要关注的性能属性有:吞吐量、延迟、内存占用。其中:
(1) 吞吐量:是评价垃圾收集器能力的重要指标之一,指不考虑垃圾收集引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标。
(2) 延迟:也是评价垃圾收集器能力的重要指标,度量标准是缩短由于垃圾收集引起的停顿时间或完全消除因垃圾收集所引起的停顿,避免应用运行时发生抖动。
(3) 内存占用:垃圾收集器流畅运行所需要的内存数量。
这其中任何一个属性性能的提高几乎都是以另一个或两个属性性能的损失作代价的。换句话说,某一个属性上的性能提高总是牺牲另一个或两个属性。然而,对大多数应用来说,极少出现这三个属性的重要程度都同等的情况。很多时候,某一个或两个属性的性能要比另一个重要。哪个属性最重要,并将其映射到应用的系统需求,对应用而言非常重要。
同一个JVM中,可能包含多种垃圾收集器实现。在选择垃圾收集器时,要根据应用的需求,进行一个初步的选择。在HotSpot VM中,如果应用对停顿时间要求较为严格(即不希望因为垃圾收集而导致过多的暂停),那么可能需要选择那些停顿时间较短的垃圾收集器,如CMS收集器或G1收集器。相反,如果应用对停顿时间要求不那么严格,可以考虑使用串行收集器或并行收集器,它们在垃圾收集时可能会暂停所有工作线程。如果对较小的堆或较低配置的硬件,可能更适合使用简单的串行收集器或者并行收集器。对于大内存堆和多核CPU的环境,可以考虑使用G1等垃圾收集器,它们更适合大规模的堆和高配置的硬件。垃圾收集器的选择,要根据业务的特征,进行充分的测试。初步选择后,如果经过测试后,并不能达到预期,则要考虑换用垃圾收集器,并重新进行测试。
在进行垃圾收集验证时,一般从默认垃圾收集器开始。Java 8默认的垃圾收集器是Parallel Scavenge和Parallel Old。这是Oracle JDK 8中的默认设置,适用于大多数应用程序场景。但在某些特定场景下,可能需要选择其他更适合的垃圾收集器,如CMS收集器或G1收集器。指定CMS收集器或G1收集器的示例命令如下: