总览

在本快速教程中,我们将探索可用于配置Java虚拟机的最常见的选项。

显式设定堆内存 –Xms和-Xmx选项

与性能有关的最常见实践之一是根据应用程序要求初始化堆内存。

这就是为什么我们应该指定最小和最大堆。以下参数可用于实现此目的:

-Xms<heap size>[unit] 
-Xmx<heap size>[unit]

此处,unit表示要初始化内存(由堆大小指示)的单位。对于GB,单位可以标记为“g”,对于MB,单位可以标记为“m”,对于KB,单位可以标记为“k”。

例如,如果我们要为JVM分配最小2GB和最大5GB,我们需要编写:

-Xms2G -Xmx5G

从Java 8开始,未定义Metaspace的大小。一旦达到全局限制,JVM会自动增加它。但是,为了克服任何不必要的不​​稳定,我们可以使用以下方法设置元空间大小:

-XX:MaxMetaspaceSize=<metaspace size>[unit]

在这里,元空间大小表示我们要分配给元空间的内存。

根据Oracle指南,在总可用内存之后,第二大影响因素是为Young Generation保留的堆的比例。默认情况下,YG的最小大小为1310 MB,最大大小为无限。

我们可以明确地分配它们:

-XX:NewSize=<young size>[unit] 
-XX:MaxNewSize=<young size>[unit]

垃圾收集

为了提高应用程序的稳定性,选择正确的垃圾收集算法至关重要。

JVM具有四种类型的GC实现:

  • Serial Garbage Collector
  • Parallel Garbage Collector
  • CMS Garbage Collector - 从Java 9开始,不建议使用CMS垃圾收集器。此外,Java 14完全放弃了CMS支持。
  • G1 Garbage Collector

可以使用以下参数声明这些实现:

-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+USeParNewGC
-XX:+UseG1GC

GC日志

为了严格监控应用程序的运行状况,我们应该始终检查JVM的垃圾回收性能。最简单的方法是以人类可读的格式记录GC活动。

使用以下参数,我们可以记录GC活动:

-XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=< number of log files > 
-XX:GCLogFileSize=< file size >[ unit ]
-Xloggc:/path/to/gc.log

UseGCLogFileRotation 指定了日志文件滚动策略,与log4j,slf4j等非常相似。NumberOfGCLogFiles表示可以在单个应用程序生命周期内写入的最大日志文件数。GCLogFileSize指定文件的最大大小。最后,loggc表示其位置。

这里要注意的是,还有两个可用的JVM参数(-XX:+ PrintGCTimeStamps-XX:+ PrintGCDateStamps)可用于在GC日志中打印按日期标记的时间戳。

例如,如果我们要分配最多10个GC日志文件(每个文件的最大大小为50 MB)并将它们存储在“/home/user/log/”位置,则可以使用以下语法:

-XX:+UseGCLogFileRotation  
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=50M 
-Xloggc:/home/user/log/gc.log

但是,问题在于,总是在后台使用一个附加的守护程序线程来监视系统时间。此行为可能会产生一些性能瓶颈;因此,在生产中最好不要使用此参数。

处理内存不足

大型应用程序遇到内存不足错误非常普遍,而错误又导致应用程序崩溃。这是非常关键的情况,很难照搬以解决问题。

这就是JVM带有一些参数的原因,这些参数将堆内存快照转储到物理文件中,可用于以后查找泄漏:

-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=./java_pid<pid>.hprof
-XX:OnOutOfMemoryError="< cmd args >;< cmd args >" 
-XX:+UseGCOverheadLimit

这里有几点要注意:

  • HeapDumpOnOutOfMemoryError指示JVM在OutOfMemoryError情况下将堆转储到物理文件中
  • HeapDumpPath表示要写入文件的路径;可以提供任何文件名;但是,如果JVM在名称中找到 <pid> 标记,则导致内存不足错误的当前进程的进程ID将以.hprof格式附加到文件名中。
  • OnOutOfMemoryError用于发出紧急命令以在出现内存不足错误时执行;在cmd args的空格中应使用正确的命令。例如,如果要在内存不足时立即重新启动服务器,则可以设置参数:
    -XX:OnOutOfMemoryError="shutdown -r"
    
  • UseGCOverheadLimit是一项策略,用于限制在抛出OutOfMemory错误之前,VM在GC中花费的时间比例

32/64位

在同时安装了32位和64位软件包的OS环境中,JVM会自动选择32位环境软件包。

如果要手动将环境设置为64位,可以使用以下参数进行设置:

-d<OS bit>

OS位可以是32或64。有关此的更多信息,请参见此处

其他

  • -server:启用“服务器Hotspot VM”;默认情况下,此参数在64位JVM中使用
  • -XX:+UseStringDeduplication: Java 8u20引入了此JVM参数,以通过创建太多相同String的实例来减少不必要的内存使用。这通过将重复的String值减少为单个全局char []数组来优化堆内存
  • -XX:+UseLWPSynchronization:设置基于LWP(轻量级进程)的同步策略,而不是基于线程的同步
  • -XX:LargePageSizeInBytes:设置用于Java堆的大页面大小;它采用GB / MB / KB作为参数;页面大小较大时,我们可以更好地利用虚拟内存硬件资源;但是,这可能会导致PermGen的空间更大,从而迫使其减小Java堆空间的大小。
  • -XX:MaxHeapFreeRatio:设置GC之后释放堆的最大百分比,以避免收缩。
  • -XX:MinHeapFreeRatio:设置GC之后释放堆的最小百分比以避免扩展;要监视堆使用情况,可以使用JDK附带的VisualVM
  • -XX:SurvivorRatio:eden/survivor空间大小之比 -– 例如, -XX:SurvivorRatio=6 将每个survivor空间与eden空间之比设置为1:6,
  • -XX:+UseLargePages:如果系统支持,则使用大页面内存;请注意,如果使用此JVM参数, OpenJDK 7倾向于崩溃
  • -XX:+UseStringCache:启用字符串池中可用的常用分配字符串的缓存
  • -XX:+UseCompressedStrings:对可使用纯ASCII格式表示的String对象使用byte []类型
  • -XX:+OptimizeStringConcat:尽可能优化String连联操作

总结

在这篇简短的文章中,我们了解了一些重要的JVM参数 – 可用于调整和改善常规应用程序性能。

其中一些也可以用于调试目的。

如果您想更详细地探索参考参数,可以从这里开始。

Guide to the Most Important JVM Parameters