从ES的JVM配置起步思考JVM常见参数优化

发布于:2024-11-23 ⋅ 阅读:(14) ⋅ 点赞:(0)

目录

一、真实查看参数

(一)-XX:+PrintCommandLineFlags

(二)-XX:+PrintFlagsFinal

二、堆空间的配置

(一)默认配置

(二)配置Elasticsearch堆内存时,将初始大小设置为物理内存的一半(重点理解)

存储型服务(如 Elasticsearch)

计算型服务(如普通 Web 服务)

存储型服务(如 Elasticsearch)和 计算型服务(如普通 Web 服务)抉择

抉择结论分析

(三)堆外内存划分说明

元空间(Metaspace)

JIT编译后代码存放

本地内存

直接内存

JNI内存

(四)平常的应用服务较常用的调整分代比例

三、日志参数配置

(一)Java 8 jvm.options文件中的JVM日志参数配置

(二)Java 9+ jvm.options文件中的JVM日志参数配置

四、异常日志记录

(一)HeapDumpOnOutOfMemoryError

(二)HeapDumpPath

(三)ErrorFile

(四)作用和意义

五、垃圾回收器配置

(一)Java 8中Elasticsearch默认使用CMS垃圾回收器

(二)Java 9及以上版本垃圾回收器变化

六、额外自定义参数

(一)-Xss 参数

(二)-XX:-OmitStackTraceInFastThrow

(三)-Djava.awt.headless

七、分布式列存数据库Cassandra JVM参数简单回顾


干货分享,感谢您的阅读!

Java 8目前仍然是许多企业中主要使用的版本之一,尤其是对于比较保守的公司。在过去,CMS (Concurrent Mark-Sweep) 垃圾回收器在Java 8中是一种常见选择,因为它在某些场景下能够提供较好的性能。

然而,随着Java版本的不断更新,一些旧的特性和组件被淘汰或替代,比如CMS。Java 14中正式废弃了CMS,而新的垃圾回收器,如ZGC和G1,逐渐成为了主流选择。ZGC和G1在处理大内存堆和低停顿时间方面表现出色,适用于现代应用程序的需求。

另外,自Java 9以后,Java的发布模式也发生了变化,从长期支持(LTS)版本切换到了更频繁的发布,大约每六个月发布一次。Java 8和Java 11是目前支持的LTS版本,它们提供了更长时间的支持和维护,适合希望保持稳定性和兼容性的企业和组织使用。

关于JVM相关的优化和配置我们之前提到过很多基本的知识内容,比如如下的几篇重点内容,有时间可以在回顾一下:

涉猎内容 具体链接
基本知识内容 Java回收垃圾的基本过程与常用算法_java垃圾回收过程-CSDN博客
CMS调优和案例分析 CMS垃圾回收器介绍与优化分析案列整理总结_cms 对老年代的回收做了哪些优化设计-CSDN博客
G1调优分析 Java Hotspot G1 GC的理解总结_java g1-CSDN博客
ZGC基础和调优案例分析 垃圾回收器ZGC应用分析总结-CSDN博客
高频面试题汇总 JVM高频基本面试问题整理_jvm面试题-CSDN博客

今天我们就JVM常见优化参数为基本内容再次重新来说(主要从ES的JVM配置来强化理解)。

一、真实查看参数

JVM和垃圾回收器的参数配置是一个复杂而且经常变化的领域。很多时候,我们可能会尝试通过调整参数来优化应用程序的性能,但是如果不了解这些参数的默认值和影响,就很容易陷入误区。

在查看自己的应用真实的JVM生效参数上,我们需要先通过一下基本命令行进行了解:

(一)-XX:+PrintCommandLineFlags

-XX:+PrintCommandLineFlags 可以打印出JVM使用的命令行标志,包括垃圾回收器类型和一些默认值。具体使用如下:

java -XX:+PrintCommandLineFlags -version

输出事例如下:

-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
openjdk version "1.8.0_41"

OpenJDK Runtime Environment (build 1.8.0_41-b04)

OpenJDK 64-Bit Server VM (build 25.40-b25, mixed mode)

简单看起信息

参数 说明
-XX=268435456 初始堆大小为 256 MB
-XX=4294967296 最大堆大小为 4 GB
-XX:+PrintCommandLineFlags 打印命令行标志,即启动JVM时使用的所有参数
-XX:+UseCompressedClassPointers 使用压缩类指针
-XX:+UseCompressedOops 使用压缩普通对象指针
-XX:-UseLargePagesIndividualAllocation 禁用大页面单独分配
-XX:+UseParallelGC 使用并行垃圾回收器

对于Java版本信息就不必解释了吧。

(二)-XX:+PrintFlagsFinal

当你在调优应用程序时,可能会试着添加一些JVM参数来提高性能。有时候,你可能会觉得添加了某个参数后,程序的运行速度明显提升了。但是,当你通过 -XX:+PrintFlagsFinal 命令来查看参数的默认值时,可能会发现这个参数的默认配置和你所设置的值并不一样,改值可能默认是不能修改的。

因此,在调整JVM参数时,特别是在不同的JVM版本和垃圾回收器上,我们应该先查看该参数的默认配置,而不是轻信他人的建议。可以通过以下命令来查看某个参数的默认值,比如使用G1垃圾回收器时是否启用了自适应大小策略:

java -XX:+PrintFlagsFinal -XX:+UseG1GC  2>&1 | grep UseAdaptiveSizePolicy

这样就能更准确地了解参数的影响,避免因为不了解默认配置而产生误解。

二、堆空间的配置

Elasticsearch是一个基于Java开发的高性能开源分布式搜索引擎,因此它的运行依赖于Java虚拟机(JVM)。在Elasticsearch的conf目录下,有一个名为jvm.options的文件,jvm.options文件是配置Elasticsearch JVM参数的地方,通过合理地配置这些参数,可以更好地发挥Elasticsearch的性能和稳定性。我们本次就堆空间配置进行学习。

(一)默认配置

JVM 的内存,分为堆和堆外内存,其中堆的大小可以通过 Xmx 和 Xms 来配置。

以下是一个简化的jvm.options文件示例,来看一下Elasticsearch官方提供的默认堆空间配置:

# Elasticsearch jvm.options configuration

# 设置初始堆大小和最大堆大小为1GB
-Xms1g
-Xmx1g

# AlwaysPreTouch参数配置
-XX:+AlwaysPreTouch

将Elasticsearch堆空间配置整合成表格:

参数 说明
-Xms1g 初始堆大小为1GB
-Xmx1g 最大堆大小为1GB,限制堆空间不超过1GB
-XX:+AlwaysPreTouch 在JVM启动时预先分配所有指定的堆内存,减少运行时的内存动态分配性能损耗

通过这些配置,Elasticsearch在启动时会使用1GB的初始堆空间,并且预先分配所有指定的堆内存,以避免运行时内存动态分配的性能损耗。

(二)配置Elasticsearch堆内存时,将初始大小设置为物理内存的一半(重点理解)

存储型服务(如 Elasticsearch)

当配置Elasticsearch堆内存时,我们通常把堆的初始化大小设置成物理内存的一半。其考虑点主要是因为一下几点原因:

1. 文件缓存需求(Page Cache 的重要性)

Elasticsearch 作为一个存储型服务,需要频繁读取和写入数据文件。操作系统的 文件缓存(Page Cache)在这里起到了关键作用,操作系统会将频繁访问的文件缓存在内存中,从而避免频繁的磁盘 I/O,提升查询和索引操作的性能。如果将大部分内存分配给 JVM 堆,则可用的文件缓存会减少,系统性能会明显下降。

因此,预留物理内存的一部分给操作系统的文件缓存是非常必要的。

2. 避免系统内存耗尽(防止 Out of Memory)

Elasticsearch 所在的服务器上还可能运行其他进程(如监控、日志采集工具)。如果堆分配过大,会导致系统内存不足,从而引发交换(swap)或 OOM(Out of Memory)异常,影响整体稳定性。

3. 降低垃圾回收(GC)的影响

JVM 堆内存过大时,垃圾回收操作会耗费更多时间,尤其是 Full GC,可能导致长时间的停顿,从而影响服务的稳定性和响应时间。通过限制堆的大小(物理内存的 1/2),可以减小 GC 的影响,并控制堆中活跃对象的数量,使 GC 更加高效。

4. 避免内存碎片化

对于Elasticsearch而言,JVM 堆大小如果动态调整,会导致内存碎片化问题,影响性能。将堆的初始大小(Xms)和最大大小(Xmx)设置为相同值,并且占物理内存的一半,可以减少动态调整带来的开销,提升性能。

将 Elasticsearch 的堆内存设置为物理内存的一半,既保证了 JVM 的运行效率,又为文件缓存和堆外内存预留了足够的空间,从而实现性能和稳定性的平衡。这种配置是 Elasticsearch 官方推荐的最佳实践

计算型服务(如普通 Web 服务)

但注意对于计算型节点,例如普通的Web服务,通常会采用将堆内存设置为物理内存的2/3,留下的1/3用于堆外内存使用。其考虑点主要是因为一下几点原因:

1.计算型节点主要依赖堆内存

  • 工作负载的特性

    • 计算型节点主要以 CPU 密集型任务为主,例如逻辑处理、业务计算和短时内存分配。
    • 这些任务的内存需求通常集中在 JVM 堆内存中,堆外内存使用相对较少。
  • 内存管理方式

    • JVM 内的对象生命周期和分配由垃圾回收器(GC)管理。通过提供更大的堆,可以容纳更多的对象,减少堆外内存的需求。

2. 减少垃圾回收(GC)停顿的频率

  • 更大的堆意味着更少的 GC较大的堆空间允许更多对象存活,减少垃圾回收的频率,特别是 Minor GC(年轻代垃圾回收)。对于计算密集型任务,这可以显著提高吞吐量和应用性能。

  • Full GC 的开销:虽然 Full GC 会消耗时间,但计算型节点的堆内存需求趋于稳定,GC 调优的目标是尽量减少频率,而非避免 GC 完全停顿

3. 堆外内存需求相对较少

  • 堆外内存用途堆外内存主要用于缓冲区(例如网络传输时的 Direct Buffer)、JNI 调用或其他低级操作。对于计算型节点,这些需求往往是固定且较小的。

  • 保留足够空间即可:将物理内存的 1/3 预留给堆外内存已经足够满足计算型服务的需求,不会因堆外内存不足而出现性能瓶颈。

4. 系统性能的整体平衡

  • 操作系统缓存需求低与存储型服务不同,计算型服务对文件缓存的依赖较低,因此无需为操作系统文件缓存预留过多的内存。这使得可以将更多的物理内存分配给堆内存。

  • 内存分配的合理性:分配更多堆内存有助于提高应用程序的计算能力,而将堆内存设置为 2/3 的比例,既保证了 JVM 的性能,又留有一定空间给操作系统和堆外内存,避免过度分配导致内存不足。

在计算型节点中,2/3 的物理内存用于 JVM 堆是一种平衡的策略,充分利用了内存资源来提高计算效率,同时为堆外内存和系统操作保留了足够的空间。相比存储型服务(堆设置为 1/2),计算型服务的内存需求集中在堆内,因此这两种场景的配置策略有所不同。

存储型服务(如 Elasticsearch)和 计算型服务(如普通 Web 服务)抉择

存储型服务(如 Elasticsearch)和 计算型服务(如普通 Web 服务)在内存配置上的本质区别的对比表格:

对比维度 存储型服务(Elasticsearch) 计算型服务(Web 服务)
主要工作负载 数据存储、查询、索引、文件操作 业务逻辑处理、计算任务、短期内存分配
内存需求 文件缓存需求大,对堆外内存依赖较高 主要依赖堆内存,文件缓存和堆外内存需求较少
文件缓存依赖性 非常高,通过操作系统文件缓存加速磁盘 I/O 较低,对文件缓存几乎没有依赖
堆内存作用 支持索引创建、查询处理,需求较少 执行计算任务,需求较高
堆外内存使用 较多,用于文件缓存、索引缓冲和网络缓冲区 较少,仅用于网络缓冲或 JNI 调用
堆内存大小配置 设置为物理内存的 1/2,预留更多内存用于文件缓存 设置为物理内存的 2/3,优先支持计算任务
垃圾回收(GC) 堆较小,GC 周期较短,减少 Full GC 停顿影响 堆较大,减少 Minor GC 次数,提高吞吐量
性能优化的侧重点 提高文件缓存性能,减少磁盘 I/O 减少 GC 停顿,提高计算效率
抉择结论分析
  1. 内存使用本质区别存储型服务强调操作系统文件缓存的性能,内存需求集中在堆外内存和文件缓存;而计算型服务主要依赖 JVM 堆内存来支持其计算密集型任务

  2. 配置策略不同

    存储型服务:堆内存设置为 物理内存的 1/2,确保操作系统有足够内存用于文件缓存,同时降低 GC 对查询和索引操作的影响计算型服务:堆内存设置为 物理内存的 2/3,尽量为计算任务分配更多内存空间,同时预留部分内存支持网络缓冲和系统操作。
  3. 选择依据

    如果服务需要频繁访问磁盘数据(如数据库或搜索引擎),选择存储型服务的内存配置策略。如果服务以逻辑计算为主(如 API、Web 服务器),选择计算型服务的内存配置策略。

通过理解两者的内存需求和优化方向,可以更好地配置 JVM 堆内存,提升系统的稳定性与性能。

(三)堆外内存划分说明

元空间(Metaspace)

元空间是用于存储类元数据的区域,例如类的结构、方法信息等。

通过设置参数 -XX:MaxMetaspaceSize-XX:MetaspaceSize,可以指定元空间的最大内存和初始化内存。

由于元空间默认是没有上限的,极端情况下,它可能会一直扩张占用操作系统剩余的内存。

JIT编译后代码存放

JIT(Just-In-Time)编译器会将Java字节码编译为本地机器代码,并存放在Code Cache中。这些代码在运行时被执行。

可以通过参数 -XX:ReservedCodeCacheSize 来限制Code Cache的大小。此外,JNI(Java Native Interface)的代码也存放在Code Cache中。

本地内存

本地内存是指其他附加在JVM进程上的内存区域,例如网络连接占用的内存、线程创建占用的内存等。在高并发应用中,这些内存累积起来可能会相当可观。

直接内存

直接内存是通过ByteBuffer类申请的,它会绕过JVM的堆内存,直接在操作系统的本地内存中分配空间。可以通过参数 -XX:MaxDirectMemorySize 来限制直接内存的大小。

JNI内存

JNI内存指的是由JNI代码通过malloc等方式在堆外分配的内存。不幸的是,JVM无法控制这部分内存的使用,它依赖于具体的JNI代码实现。

(四)平常的应用服务较常用的调整分代比例

在平常的应用服务中,我们希望得到更细粒度的控制,其中比较常用的就是调整各个分代之间的比例。

  • -Xmn 年轻代大小,默认年轻代占堆大小的 1/3。高并发快消亡场景可适当加大这个区域,对半或者更多都是可以的。但是在 G1 下,就不用再设置这个值了,它会自动调整;
  • -XX:SurvivorRatio 默认值为 8,表示伊甸区和幸存区的比例;
  • -XX:MaxTenuringThreshold 这个值在 CMS 下默认为 6,G1 下默认为 15。这个值和我们前面提到的对象提升有关,改动效果会比较明显。对象的年龄分布可以使用 -XX:+PrintTenuringDistribution 打印,如果后面几代的大小总是差不多,证明过了某个年龄后的对象总能晋升到老年代,就可以把晋升阈值设的小一些;
  • PretenureSizeThreshold 超过一定大小的对象,将直接在老年代分配,不过这个参数用得不是很多。

三、日志参数配置

在Java 9之前,JVM的日志输出主要依赖于选项-Xloggc-XX:+PrintGC等参数。这些参数的配置方式相对固定,并且在不同的Java版本中保持一致。但由于Java 9引入了JEP 158,即Unified JVM Logging(重新设计和重构了JVM的日志系统),提供了更丰富的选项和功能,包括不同类型日志的过滤、格式化、标签等,使用了-Xlog参数来配置日志输出。

为了适应Java 9引入的新日志系统,Elasticsearch在jvm.options文件中针对Java 9以上版本采用了新的参数配置方式,而对于Java 8则保留了之前的参数配置方式,以保持与旧版Java兼容。

(一)Java 8 jvm.options文件中的JVM日志参数配置

# Elasticsearch 7.x JVM日志参数配置 (Java 8)

# 打印GC的详细信息
-XX:+PrintGCDetails

# 打印GC发生的时间戳
-XX:+PrintGCDateStamps

# 打印对象年龄分布
-XX:+PrintTenuringDistribution

# 在GC期间应用程序停止的时间
-XX:+PrintGCApplicationStoppedTime

# 将GC日志输出到指定文件
-Xloggc:logs/gc.log

# 启用GC日志文件轮换
-XX:+UseGCLogFileRotation

# GC日志文件的数量
-XX:NumberOfGCLogFiles=32

# 单个GC日志文件的大小
-XX:GCLogFileSize=64m

(二)Java 9+ jvm.options文件中的JVM日志参数配置

# Elasticsearch 7.x JVM日志参数配置 (Java 9+)

# 这是Java 9及以上版本的新格式,使用了-Xlog参数,用于配置GC日志输出。
# 这个参数配置了不同类型的GC日志输出,包括gc、gc+age、safepoint,并将日志输出到指定的文件中。
# 参数filecount=32指定了GC日志文件的数量,filesize=64m指定了单个GC日志文件的大小。

-Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m

具体说明可见上方配置注释标注。

四、异常日志记录

在Elasticsearch的jvm.options文件中,针对异常情况记录的JVM参数配置示例:

# Elasticsearch JVM异常情况记录参数配置

# 在内存溢出时生成堆转储文件
-XX:+HeapDumpOnOutOfMemoryError

# 指定堆转储文件的保存路径
-XX:HeapDumpPath=data

# 指定错误日志文件的保存路径
-XX:ErrorFile=logs/hs_err_pid%p.log

在Java应用程序的运行过程中,常见的异常情况如内存溢出(OutOfMemoryError,OOM),其可能导致应用程序崩溃或性能下降。为了有效地诊断和解决这类问题,以上这些参数用于在异常情况下记录堆转储文件(Heap Dump)和错误日志文件(Error Log),以便在发生问题时进行分析和诊断。

(一)HeapDumpOnOutOfMemoryError

用于指示在发生内存溢出错误时自动生成堆转储文件(Heap Dump)。堆转储文件是Java堆的快照,记录了在程序运行期间分配的所有对象以及它们的引用关系。通过分析堆转储文件,可以深入了解内存使用情况,找到内存泄漏或者其他造成内存溢出的原因。

(二)HeapDumpPath

用于指定生成的堆转储文件的保存路径。一般情况下,堆转储文件会比较大,因此需要将它们保存在一个足够大的磁盘空间中,以便后续的分析和处理。

(三)ErrorFile

用于指定错误日志文件的保存路径。当Java应用程序发生严重错误时(如虚拟机错误或崩溃),会生成错误日志文件,其中包含了错误的详细信息和堆栈跟踪。这些信息对于分析和排查问题都非常重要。

(四)作用和意义

配置这些参数可以帮助我们在发生内存溢出或其他严重错误时快速定位问题。一旦发生OOM错误,JVM就会自动在指定路径下生成堆转储文件,我们可以使用内存分析工具(如MAT)来打开这些文件,深入分析内存使用情况,找到问题的根源。同时,错误日志文件也可以提供有用的调试信息,帮助我们了解错误发生的原因和上下文。

五、垃圾回收器配置

(一)Java 8中Elasticsearch默认使用CMS垃圾回收器

典型的Elasticsearch 7.x版本中,Elasticsearch的默认配置确实使用了CMS(Concurrent Mark-Sweep)垃圾回收器,尤其是在Java 8环境中。在Elasticsearch的默认配置文件jvm.options中,你可以看到CMS相关的JVM参数配置:

## GC configuration
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
  • UseConcMarkSweepGC,表示年轻代使用 ParNew,老年代的用 CMS 垃圾回收器
  • -XX:CMSInitiatingOccupancyFraction 由于 CMS 在执行过程中,用户线程还需要运行,那就需要保证有充足的内存空间供用户使用。如果等到老年代空间快满了,再开启这个回收过程,用户线程可能会产生“Concurrent Mode Failure”的错误,这时会临时启用 Serial Old 收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了(STW)。
  • -XX:+UseCMSInitiatingOccupancyOnly,只有在堆空间使用率达到指定阈值时才触发CMS垃圾回收。此参数必须与-XX:CMSInitiatingOccupancyFraction配合使用,以确保CMS只在指定的阈值时启动。

另外,对于 CMS 垃圾回收器,常用的还有下面的配置参数:

  • -XX:ExplicitGCInvokesConcurrent 当代码里显示的调用了 System.gc(),实际上是想让回收器进行FullGC,如果发生这种情况,则使用这个参数开始并行 FullGC。建议加上。
  • -XX:CMSFullGCsBeforeCompaction 默认为 0,就是每次FullGC都对老年代进行碎片整理压缩,建议保持默认。
  • -XX:CMSScavengeBeforeRemark 开启或关闭在 CMS 重新标记阶段之前的清除(YGC)尝试。可以降低 remark 时间,建议加上。
  • -XX:+ParallelRefProcEnabled 可以用来并行处理 Reference,以加快处理速度,缩短耗时。

CMS 垃圾回收器,已经在 Java14 中被移除,由于它的 GC 时间不可控,有条件应该尽量避免使用。

(二)Java 9及以上版本垃圾回收器变化

对于Java 9及以上版本,由于垃圾回收器和日志系统的变化,Elasticsearch的jvm.options文件也会有所不同,使用新的-Xlog参数配置GC日志,并可能使用不同的垃圾回收器(如G1 GC):

## G1 GC 配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=16m
-XX:InitiatingHeapOccupancyPercent=45
-XX:+ParallelRefProcEnabled

在这里,使用了G1垃圾回收器,并配置了相应的参数来优化其行为。Elasticsearch可以在不同的Java版本中,利用适当的垃圾回收策略和日志记录方式来保证其性能和稳定性。

主要的配置参数:

  • -XX:MaxGCPauseMillis 设置目标停顿时间,G1 会尽力达成。
  • -XX:G1HeapRegionSize 设置小堆区大小。这个值为 2 的次幂,不要太大,也不要太小。如果是在不知道如何设置,保持默认。
  • -XX:InitiatingHeapOccupancyPercent 当整个堆内存使用达到一定比例(默认是45%),并发标记阶段就会被启动。
  • -XX:ConcGCThreads 并发垃圾收集器使用的线程数量。默认值随 JVM 运行的平台不同而不同。不建议修改。

号外:JVM 支持非常多的垃圾回收器,有兴趣可查看其他资料,重点的三个在开篇已有推荐。

六、额外自定义参数

额外的自定义参数通常用于调整和优化Elasticsearch的性能、稳定性和安全性,以满足特定的应用场景和需求。这些参数可能涉及到底层的Java虚拟机(JVM)、网络设置、日志系统以及其他相关的配置。以下是这些参数在Elasticsearch jvm.options 文件中的示例配置:

## 设置每个Java虚拟机栈的容量
-Xss1m

## 确保异常打印完整堆栈信息
-XX:-OmitStackTraceInFastThrow

## 启用Headless模式
-Djava.awt.headless=true

## Java 9及以上版本的参数
9-:-Djava.locale.providers=COMPAT

## 设置文件编码为UTF-8
-Dfile.encoding=UTF-8

## 设置网络地址缓存时间
-Des.networkaddress.cache.ttl=60
-Des.networkaddress.cache.negative.ttl=10

## Netty相关参数
-Dio.netty.noUnsafe=true
-Dio.netty.noKeySetOptimization=true
-Dio.netty.recycler.maxCapacityPerThread=0

## Log4j相关参数
-Dlog4j.shutdownHookEnabled=false
-Dlog4j2.disable.jmx=true

## 设置临时目录路径
-Djava.io.tmpdir=${ES_TMPDIR}

## 禁用JNA系统调用
-Djna.nosys=true

我们选取几个简单说一下。

(一)-Xss 参数

-Xss 参数用于设置每个线程的Java虚拟机栈(JVM Stack)的大小。JVM栈是线程私有的内存区域,用于存储线程执行方法时的局部变量、方法参数、方法调用和返回信息等。栈的大小会影响到线程的最大深度,即线程可以嵌套调用的方法数量。

在默认情况下,每个线程的JVM栈大小由 -XX:ThreadStackSize 参数决定,而 -Xss 参数则是设置所有线程的JVM栈大小,其值会覆盖 -XX:ThreadStackSize 的设定。在具体使用时,两者是等价的,只是 -Xss 更为简洁。

例如, -Xss1m 表示将每个线程的JVM栈大小设置为1MB。这意味着每个线程在执行时最多只能使用1MB的栈空间。如果应用程序的线程数量较多,且每个线程的方法调用深度较大,那么设置较小的栈大小可能会导致栈溢出(StackOverflowError)异常。

在配置该参数时,需要根据具体的应用场景和需求进行合理的调整。如果应用程序的方法调用深度较大或者并发线程较多,可以适当增加JVM栈的大小以避免栈溢出问题;反之,如果线程数量较少或者方法调用深度不大,可以适当减小JVM栈的大小以节省内存空间。

(二)-XX:-OmitStackTraceInFastThrow

用于调整异常处理行为的JVM参数。当设置为 -XX:-OmitStackTraceInFastThrow 时,它会关闭快速异常抛出时省略堆栈信息的优化,即在发生异常时完整地打印异常的堆栈信息。

在默认情况下,JVM会对某些频繁抛出的异常(如 NullPointerExceptionArrayIndexOutOfBoundsException 等)进行优化,省略异常堆栈信息以提高性能。这种优化能够减少异常抛出时的开销,但也使得调试时定位问题变得更加困难,因为无法得知异常发生的具体位置和上下文信息。

但需要注意的是,关闭异常快速抛出的优化会带来一定的性能损耗,因为在抛出异常时需要额外的开销来生成完整的堆栈信息。因此,在生产环境中,可能需要权衡性能和调试方便性之间的平衡,根据具体情况来决定是否关闭该优化。

(三)-Djava.awt.headless

-Djava.awt.headless=true 是一个Java系统属性,用于在启动Java虚拟机(JVM)时设置系统参数。这个参数的作用是告诉Java虚拟机当前运行的环境是否是 Headless 模式。

在Headless模式下,操作系统缺少了显示设备、键盘或鼠标等交互设备,因此Java应用程序需要使用软件方式来模拟这些设备。这种模式通常用于服务器环境,因为在服务器上通常没有图形界面或人机交互设备,只需要执行后台任务,如处理数据、运行服务等。

设置 -Djava.awt.headless=true 后,Java虚拟机将以无图形界面的方式运行,不会尝试去创建图形界面相关的窗口、组件或事件。这有助于提高性能和减少资源占用,因为不需要加载图形相关的库和模块,也不会尝试与图形系统交互。

在一些场景下,特别是服务器端的Java应用程序,启用Headless模式可以提高系统的稳定性和性能。这样的应用程序通常是以后台服务的形式运行,不需要图形界面,因此启用Headless模式可以更好地适应环境并节省系统资源。

七、分布式列存数据库Cassandra JVM参数简单回顾

Cassandra 是一个高性能的分布式列存数据库,广泛应用于需要高吞吐量和低延迟的大规模数据存储和检索场景。Cassandra 使用 Gossip 协议进行节点间通信和集群状态维护。

Cassandra 的 JVM 参数配置文件 jvm.options 每个参数配置如下:

# 堆内存设置
-Xms4G
-Xmx4G

# GC 日志配置
-XX:+UseG1GC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintPromotionFailure
-Xloggc:/var/log/cassandra/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=10M

# 性能优化
-XX:+AlwaysPreTouch
-XX:+UseTLAB
-XX:+ResizeTLAB
-XX:+PerfDisableSharedMem

# G1GC 特定配置
-XX:MaxGCPauseMillis=500
-XX:G1HeapRegionSize=16M
-XX:InitiatingHeapOccupancyPercent=70

# 线程栈设置
-Xss256k

# 异常处理
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/lib/cassandra/java_oom.hprof
-XX:ErrorFile=/var/log/cassandra/hs_err_pid%p.log

# JMX 配置
-Dcom.sun.management.jmxremote.port=7199
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

# 本地配置
-Djava.library.path=/usr/share/cassandra/lib/sigar-bin
-Dcassandra.jmx.local.port=7199

# 头部模式
-Djava.awt.headless=true