千家信息网

怎么理解JVM启动参数

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,怎么理解JVM启动参数,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。因为Hotspot JDK提供的参数默认值,在小版本之间不断变化
千家信息网最后更新 2026年11月04日怎么理解JVM启动参数

怎么理解JVM启动参数,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

因为Hotspot JDK提供的参数默认值,在小版本之间不断变化,参数之间也会互相影响。而且,服务器配置不同,都可能影响最后的效果。所以千万不要迷信网上的某篇文章(包括这篇)里面的参数配置,一切的配置都需要自己亲身测试一番才能用。

针对于JVM参数默认值不断变化,可以使用-XX:+PrintFlagsFinal打印当前环境JVM参数默认值,比如:java -XX:PrintFlagsFinal -version,也可以用java [生产环境参数] -XX:+PrintFlagsFinal -version | grep [待查证的参数]查看具体的参数数据。

这里是一个8G服务器的参数,JDK版本信息如下:

java version "1.8.0_73"
Java(TM) SE Runtime Environment (build 1.8.0_73-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.73-b02, mixed mode)

堆设置

堆内存设置应该算是一个Java程序猿的基本素养,最少也得修改过Xms、Xmx、Xmn这三个参数了。但是一个2G堆大小的JVM,可能总共占用多少内存的?

堆内存 + 线程数 * 线程栈 + 永久代 + 二进制代码 + 堆外内存

2G + 1000 * 1M + 256M + 48/240M + (~2G) = 5.5G (3.5G)
- 堆内存: 存储Java对象,默认为物理内存的1/64
- 线程栈: 存储局部变量(原子类型,引用)及其他,默认为1M
- 永久代: 存储类定义及常量池,注意JDK7/8的区别
- 二进制代码:JDK7与8,打开多层编译时的默认值不一样,从48到240M
- 堆外内存: 被Netty,堆外缓存等使用,默认最大值约为堆内存大小

也就是说,堆内存设置为2G,那一个有1000个线程的JVM可能需要占5.5G,在考虑系统占用、IO占用等等各种情况,一台8G的服务器,也就启动一个服务了。当然,如果线程数少、并发不高、压力不大,还是可以启动多个,而且也可以把堆内存降低。

-Xms2g 与 -Xmx2g:堆内存大小,第一个是最小堆内存,第二个是最大堆内存,比较合适的数值是2-4g,再大就得考虑GC时间
-Xmn1g 或 (-XX:NewSize=1g 和 -XX:MaxNewSize=1g) 或 -XX:NewRatio=1:设置新生代大小,JDK默认新生代占堆内存大小的1/3,也就是-XX:NewRatio=2。这里是设置的1g,也就是-XX:NewRatio=1。可以根据自己的需要设置。
-XX:MetaspaceSize=128m 和 -XX:MaxMetaspaceSize=512m,JDK8的永生代几乎可用完机器的所有内存,为了保护服务器不会因为内存占用过大无法连接,需要设置一个128M的初始值,512M的最大值保护一下。
-XX:SurvivorRatio:新生代中每个存活区的大小,默认为8,即1/10的新生代, 1/(SurvivorRatio+2),有人喜欢设小点省点给新生代,但要避免太小使得存活区放不下临时对象而要晋升到老生代,还是从GC Log里看实际情况了。
-Xss256k:在堆之外,线程占用栈内存,默认每条线程为1M。存放方法调用出参入参的栈、局部变量、标量替换后的局部变量等,有人喜欢设小点节约内存开更多线程。但反正内存够也就不必要设小,有人喜欢再设大点,特别是有JSON解析之类的递归调用时不能设太小。
-XX:MaxDirectMemorySize:堆外内存/直接内存的大小,默认为堆内存减去一个Survivor区的大小。
-XX:ReservedCodeCacheSize:JIT编译后二进制代码的存放区,满了之后就不再编译。默认开多层编译240M,可以在JMX里看看CodeCache的大小。

GC设置

目前比较主流的GC是CMS和G1,有大神建议以8G为界。(据说JDK 9默认的是G1)。因为应用设置的内存都比较小,所以选择CMS收集器。下面的参数也是针对CMS收集器的,等之后如果有需要,再补充G1收集器的参数。
CMS设置

-XX:+UseConcMarkSweepGC:启用CMS垃圾收集器
-XX:CMSInitiatingOccupancyFraction=80 与 -XX:+UseCMSInitiatingOccupancyOnly:两个参数需要配合使用,否则第一个参数的75只是一个参考值,JVM会重新计算GC的时间。
-XX:MaxTenuringThreshold=15:对象在Survivor区熬过多少次Young GC后晋升到年老代,默认是15。Young GC是最大的应用停顿来源,而新生代里GC后存活对象的多少又直接影响停顿的时间,所以如果清楚Young GC的执行频率和应用里大部分临时对象的最长生命周期,可以把它设的更短一点,让其实不是临时对象的新生代长期对象赶紧晋升到年老代。
-XX:-DisableExplicitGC:允许使用System.gc()主动调用GC。这里需要说明下,有的JVM优化建议是设置-XX:-DisableExplicitGC,关闭手动调用System.gc()。这是应为System.gc()是触发Full GC,频繁的Full GC会严重影响性能。但是很多NIO框架,比如Netty,会使用堆外内存,如果没有Full GC的话,堆外内存就无法回收。如果不主动调用System.gc(),就需要等到JVM自己触发Full GC,这个时候,就可能引起长时间的停顿(STW),而且机器负载也会升高。所以不能够完全禁止System.gc(),又得缩短Full GC的时间,那就使用-XX:+ExplicitGCInvokesConcurrent或-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses选项,使用CMS收集器来触发Full GC。这两个选项需要配合-XX:+UseConcMarkSweepGC使用。
-XX:+ExplicitGCInvokesConcurrent:使用System.gc()时触发CMS GC,而不是Full GC。默认是不开启的,只有使用-XX:+UseConcMarkSweepGC选项的时候才能开启这个选项。
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses:使用System.gc()时,永久代也被包括进CMS范围内。只有使用-XX:+UseConcMarkSweepGC选项的时候才能开启这个选项。
-XX:+ParallelRefProcEnabled:默认为false,并行的处理Reference对象,如WeakReference,除非在GC log里出现Reference处理时间较长的日志,否则效果不会很明显。
-XX:+ScavengeBeforeFullGC:在Full GC执行前先执行一次Young GC。
-XX:+UseGCOverheadLimit: 限制GC的运行时间。如果GC耗时过长,就抛OOM。
-XX:+UseParallelGC:设置并行垃圾收集器
-XX:+UseParallelOldGC:设置老年代使用并行垃圾收集器
-XX:-UseSerialGC:关闭串行垃圾收集器
-XX:+CMSParallelInitialMarkEnabled 和 -XX:+CMSParallelRemarkEnabled:降低标记停顿
-XX:+CMSScavengeBeforeRemark:默认为关闭,在CMS remark前,先执行一次minor GC将新生代清掉,这样从老生代的对象引用到的新生代对象的个数就少了,停止全世界的CMS remark阶段就短一些。如果看到GC日志里remark阶段的时间超长,可以打开此项看看有没有效果,否则还是不要打开了,白白多了次YGC。
-XX:CMSWaitDuration=10000:设置垃圾收集的最大时间间隔,默认是2000。
-XX:+CMSClassUnloadingEnabled:在CMS中清理永久代中的过期的Class而不等到Full GC,JDK7默认关闭而JDK8打开。看自己情况,比如有没有运行动态语言脚本如Groovy产生大量的临时类。它会增加CMS remark的暂停时间,所以如果新类加载并不频繁,这个参数还是不开的好。

GC日志

GC过程可以通过GC日志来提供优化依据。

-XX:+PrintGCDetails:启用gc日志打印功能
-Xloggc:/path/to/gc.log:指定gc日志位置
-XX:+PrintHeapAtGC:打印GC前后的详细堆栈信息
-XX:+PrintGCDateStamps:打印可读的日期而不是时间戳
-XX:+PrintGCApplicationStoppedTime:打印所有引起JVM停顿时间,如果真的发现了一些不知什么的停顿,再临时加上-XX:+PrintSafepointStatistics -XX: PrintSafepointStatisticsCount=1找原因。
-XX:+PrintGCApplicationConcurrentTime:打印JVM在两次停顿之间正常运行时间,与-XX:+PrintGCApplicationStoppedTime一起使用效果更佳。
-XX:+PrintTenuringDistribution:查看每次minor GC后新的存活周期的阈值
-XX:+UseGCLogFileRotation 与 -XX:NumberOfGCLogFiles=10 与 -XX:GCLogFileSize=10M:GC日志在重启之后会清空,但是如果一个应用长时间不重启,那GC日志会增加,所以添加这3个参数,是GC日志滚动写入文件,但是如果重启,可能名字会出现混乱。
-XX:PrintFLSStatistics=1:打印每次GC前后内存碎片的统计信息

其他参数设置

-ea:启用断言,这个没有什么好说的,可以选择启用,或这选择不启用,没有什么大的差异。完全根据自己的系统进行处理。
-XX:+UseThreadPriorities:启用线程优先级,主要是因为我们可以给予周期性任务更低的优先级,以避免干扰客户端工作。在我当前的环境中,是默认启用的。
-XX:ThreadPriorityPolicy=42:允许降低线程优先级
-XX:+HeapDumpOnOutOfMemoryError:发生内存溢出是进行heap-dump
-XX:HeapDumpPath=/path/to/java_pid.hprof:这个参数与-XX:+HeapDumpOnOutOfMemoryError共同作用,设置heap-dump时内容输出文件。
-XX:ErrorFile=/path/to/hs_err_pid.log:指定致命错误日志位置。一般在JVM发生致命错误时会输出类似hs_err_pid.log的文件,默认是在工作目录中(如果没有权限,会尝试在/tmp中创建),不过还是自己指定位置更好一些,便于收集和查找,避免丢失。
-XX:StringTableSize=1000003:指定字符串常量池大小,默认值是60013。对Java稍微有点常识的应该知道,字符串是常量,创建之后就不可修改了,这些常量所在的地方叫做字符串常量池。如果自己系统中有很多字符串的操作,且这些字符串值比较固定,在允许的情况下,可以适当调大一些池子大小。
-XX:+AlwaysPreTouch:在启动时把所有参数定义的内存全部捋一遍。使用这个参数可能会使启动变慢,但是在后面内存使用过程中会更快。可以保证内存页面连续分配,新生代晋升时不会因为申请内存页面使GC停顿加长。通常只有在内存大于32G的时候才会有感觉。
-XX:-UseBiasedLocking:禁用偏向锁(在存在大量锁对象的创建且高度并发的环境下(即非多线程高并发应用)禁用偏向锁能够带来一定的性能优化)
-XX:AutoBoxCacheMax=20000:增加数字对象自动装箱的范围,JDK默认-128~127的int和long,超出范围就会即时创建对象,所以,增加范围可以提高性能,但是也是需要测试。
-XX:-OmitStackTraceInFastThrow:不忽略重复异常的栈,这是JDK的优化,大量重复的JDK异常不再打印其StackTrace。但是如果系统是长时间不重启的系统,在同一个地方跑了N多次异常,结果就被JDK忽略了,那岂不是查看日志的时候就看不到具体的StackTrace,那还怎么调试,所以还是关了的好。
-XX:+PerfDisableSharedMem:启用标准内存使用。JVM控制分为标准或共享内存,区别在于一个是在JVM内存中,一个是生成/tmp/hsperfdata_{userid}/{pid}文件,存储统计数据,通过mmap映射到内存中,别的进程可以通过文件访问内容。通过这个参数,可以禁止JVM写在文件中写统计数据,代价就是jps、jstat这些命令用不了了,只能通过jmx获取数据。但是在问题排查是,jps、jstat这些小工具是很好用的,比jmx这种很重的东西好用很多,所以需要自己取舍。这里有个GC停顿的例子。
-Djava.net.preferIPv4Stack=true:这个参数是属于网络问题的一个参数,可以根据需要设置。在某些开启ipv6的机器中,通过InetAddress.getLocalHost().getHostName()可以获取完整的机器名,但是在ipv4的机器中,可能通过这个方法获取的机器名不完整,可以通过这个参数来获取完整机器名。

大神给出的例子

下面贴上大神给出的例子,可以参考使用,不过还是建议在自己的环境中有针对的验证之后再使用,毕竟大神的环境和自己的环境还是不同。
性能相关

-XX:-UseBiasedLocking -XX:-UseCounterDecay -XX:AutoBoxCacheMax=20000
-XX:+PerfDisableSharedMem(可选) -XX:+AlwaysPreTouch -Djava.security.egd=file:/dev/./urandom
内存大小相关(JDK7)

-Xms4096m -Xmx4096m -Xmn2048m -XX:MaxDirectMemorySize=4096m
-XX:PermSize=128m -XX:MaxPermSize=512m -XX:ReservedCodeCacheSize=240M

如果使用jdk8,就把-XX:PermSize=128m -XX:MaxPermSize=512m换成-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m,正如前面所说的,这两套参数是为了保证安全的,建议还是加上。

CMS GC相关

-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly -XX:MaxTenuringThreshold=6
-XX:+ExplicitGCInvokesConcurrent -XX:+ParallelRefProcEnabled
GC日志相关

-Xloggc:/dev/shm/app-gc.log -XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCDateStamps -XX:+PrintGCDetails
异常日志相关

-XX:-OmitStackTraceInFastThrow -XX:ErrorFile=${LOGDIR}/hs_err_%p.log
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOGDIR}/
JMX相关

-Dcom.sun.management.jmxremote.port=${JMX_PORT} -Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
参考文章

Java性能优化指南1.8版,及唯品会的实战
Java中的逃逸分析和TLAB以及Java对象分配
The Four Month Bug: JVM statistics cause garbage collection pauses

========================================================

Cassandra,在Linux系统中,默认的JVM启动参数

-ea
-Xms4096MB
-Xmx4096MB
-Xss128K
-XX:+UseThreadPriorities
-XX:ThreadPriorityPolicy=42
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+CMSParallelRemarkEnabled
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=1
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly

-ea 从JDK1.4开始,支持断言机制,可以用于诊断运行时问题。-ea用来启动JVM的断言机制,如果不加packagename和classname,默认运行所有包和类中的断言。如果希望进行运行某些包和类的断言,可以类似 -ea:com.foo.util进行设置。

-XX:+UseThreadPriorities 开启JAVA线程优先级的功能

-XX:ThreadPriorityPolicy JAVA线程优先级的侧脸

-XX:+HeapDumpOnOutOfMemoryError 在JVM内存不足而引发程序崩溃时,讲内存中的数据导出

-Xss128K 设置线程栈的大小,默认单位为字节,也可以用KB或MB来设置。通常操作系统分配给线程栈的默认大小为1MB。另外,也可以在JAVA CODE中创建线程对象时设置栈的大小,Thread( TheadGroup group, Runnable target, String name, long stackSize)

-XX:+UseParNewGC 缩短JVM GC执行minor收集的时间

-XX:+UseConcMarkSweepGC 缩短JVM GC执行major收集的时间

-XX:+CMSParallelRemarkEnabled 缩短JVM GC执行remark操作的中断时间

-XX:SurvivorRatio 设置young generation 在 survivor spaces中所占用的大小比例

-XX:MaxTenuringThreshold 表示一个对象如果在survivor spaces移动多少次还没有被回收就放入老年代

-XX:CMSInitiatingOccupancyFraction 表示老年代占到约百分之多少的时候开始执行CMS操作

-XX:+UseCMSInitiatingOccupancyOnly 这个参数让JVM只使用CMSInitiatingOccupancyFraction 中定义的值而不用在运行中计算

关于怎么理解JVM启动参数问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

内存 参数 大小 对象 线程 时间 日志 新生 新生代 还是 收集器 机器 环境 运行 文件 时候 系统 问题 优先级 垃圾 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 南京欣网互联网络科技有限公司 中国互联网科技股 工业互联网科技新基建 互联网科技公司发展 世界互联网领先科技成果 天下捷融互联网科技 互联网科技咨询 互联网科技素材视频竖屏 温州喔噻互联网科技有限公司 互联网金融中的现代科技 港股科技和互联网 晓花互联网科技有限公司网址 注册互联网科技公司经营范围大全 为客找房互联网科技公司怎么样 国大互联网教育科技有限公司薪资 互联网安防科技感 北京军民互联网科技公司 好易买互联网科技 黑龙江互联网科技公司 山东亿川互联网科技有限责任公司 咖啡网 苏州找大状互联网科技有限公司 互联网与新科技 深圳齐家互联网科技 互联网科技宣传片 互联网金融监管科技 互联网汽车科技小镇 济南小医互联网科技有限公司招聘 广州三三互联网科技有限公司 北京品多多互联网科技有限公司
0