• 面试必问之JVM常用参数


    概述

    面试必问系列。

    参数分类

    1. 标准参数:-,功能和输出的参数都很稳定,在将来的 JVM 版本中很可能不会改变。用javajava -help命令输出所有的标准参数
    2. 非标准参数:-X,在将来的版本中可能会改变。可用java -X来检索,不保证所有参数都可以被检索出来
    3. 非Stable参数:-XX,种类多,对于布尔类型参数,+表示激活,-表示未激活,注销;非布尔值参数,先写参数名称,然后使用=赋值:-XX:=

    常用参数

    JVM提供的参数多达几百个,随着JDK版本的迭代,有些参数会被废弃,并且会加入新的参数。参数之间也有依赖关系,即某个参数的开启(生效)需要依赖另一个参数的生效。参数有很多,不可能全部都了解,学习常用的参数即可。

    查看当前JVM的默认参数的命令行:java -XX:+PrintCommandLineFlags -version
    我的笔记本的输出:

    -XX:InitialHeapSize=266555008 -XX:MaxHeapSize=4264880128 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
    java version "1.8.0_65"
    Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
    Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)
    
    • 1
    • 2
    • 3
    • 4

    查看当前JVM支持的参数的命令行:java -XX:+PrintFlagsFinal -version
    我的笔记本的输出(有删减):

    [Global flags]
         intx AliasLevel                                = 3                                   {C2 product}
         bool BackgroundCompilation                     = true                                {pd product}
         intx CMSAbortablePrecleanWaitMillis            = 100                                 {manageable}
         intx FenceInstruction                          = 0                                   {ARCH product}
         intx InteriorEntryAlignment                    = 16                                  {C2 pd product}
         bool LIRFillDelaySlots                         = false                               {C1 pd product}
         bool PrintHeapAtGC                             = false                               {product rw}
         bool UseCompressedClassPointers               := true                                {lp64_product}
         bool ZeroTLAB                                  = false                               {product}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出的每一行表示一个XX参数,包括五列:

    1. 第一列:参数的数据类型,有:uintx、intx、bool、ccstr、double、ccstrlist
    2. 第二列:名称
    3. 第三列:=表示第四列是参数的默认值,而:=表明参数被用户或JVM赋值
    4. 第四列:值
    5. 第五列是参数的类别,manageable表示可以动态修改的参数

    命令行:java -XX:+PrintFlagsInitial,用于查看参数的初始值(默认值),输出与java -XX:+PrintFlagsFinal -version输出仅第三列不完全一致。

    另外,可以指定参数-XX:+UnlockExperimentalVMOptions-XX:+UnlockDiagnosticVMOptions来解锁任何额外的隐藏参数:
    输入命令:java -server -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version | grep experimental
    输出(有删减):

    bool AggressiveUnboxing                        = false                               {C2 experimental}
    intx PredictedLoadedClassCount                 = 0                                   {experimental}
    intx RTMAbortRatio                             = 50                                  {ARCH experimental}
    
    • 1
    • 2
    • 3

    输入命令:java -server -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version | find "diagnostic"
    输出(有删减):

    bool BindCMSThreadToCPU                        = false                               {diagnostic}
    bool C1PatchInvokeDynamic                      = true                                {C1 diagnostic}
    
    • 1
    • 2

    堆、栈、元空间

    -Xms:初始堆大小,等价于-XX:InitialHeapSize
    -Xmx最大堆大小,等价于-XX:MaxHeapSize
    初始值为JVM启动是向操作系统申请的内存大小(malloc),最大值表示,当使用的内存超过初始值后扩容的最大值。JVM配置多少内存并不是说启动后就会占用多少物理内存,因为操作系统的内存分配是惰性的。对于已申请的内存虽然会分配地址空间,但并不会直接占用物理内存,真正使用时才会映射到实际的物理内存。

    -Xmn:设置年轻代大小,相当于同时配置-XX:NewSize-XX:MaxNewSize为同一值,单位默认是字节(不加单位时),一般都会加单位
    -XX:NewSize=n:设置年轻代大小(for JDK 1.3/1.4)
    -XX:MaxNewSize:设置年轻代最大值(for JDK 1.3/1.4)
    -XX:NewRatio=n:默认值为2,设置年轻代和年老代的比值(除去持久代)。如n=3表示年轻代和年老代比值为1:3,年轻代占整个年轻代年老代和的1/4,-Xmn优先级大于-XX:NewRatio。老年代大小无法直接设置,只能通过堆大小+分配比例进行调整,新生代和老年代大小计算方式为:

    NewSize = HeapSize / NewRatio + 1
    OldSize = (HeapSize / NewRatio + 1 ) * NewRatio
    
    • 1
    • 2

    -XX:SurvivorRatio=n:这个比例在Parallel Scavenge(新生代并行回收器,JDK5以后的默认新生代回收器)回收器下是动态的,运行时会出现Eden/Survivor比例和配置的不同。默认值为8,年轻代中Eden区与两个Survivor区的比值。Survivor区有两个。如n=3表示Eden:3 Survivor:2,一个Survivor区占整个年轻代的1/5。计算方式:

    SurvivorSize(1) = YoungGenerationSize / (2 + SurvivorRatio)
    EdenSize = YoungGenerationSize / (2 + SurvivorRatio) * SurvivorRatio
    
    • 1
    • 2

    -XX:PretenureSizeThreshold:当创建的对象超过指定大小时,直接把对象分配在老年代。
    -XX:MaxTenuringThreshold:设定对象在Survivor复制的最大年龄阈值,超过阈值转移到老年代

    永久代(PermGen,持久代)两个配置参数:
    -XX:PermSize:设置永久代的初始大小,如果超出该大小,则会触发垃圾回收。此选项在JDK 8中已弃用,并由-XX:MetaspaceSize选项取代。
    -XX:MaxPermSize:设置永久代的最大值,默认是64M
    对于永久代,如果动态生成很多class的话,就很可能出现,因为永久代空间配置有限。最典型的场景是,在web开发比较多jsp页面的时候。JDK8之后,方法区存在于元空间(Metaspace)。物理内存不再与堆连续,而是直接存在于本地内存中,理论上机器内存有多大,元空间就有多大。
    此选项在JDK 8中已弃用,并由-XX:MaxMetaspaceSize选项取代。

    -Xss:每个线程的堆栈大小

    -XX:MetaspaceSize:初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放大量的空间,就适当降低该值;如果释放很少的空间,则在不超过MaxMetaspaceSize时,适当提高该值。默认大小取决于平台。

    -XX:MaxMetaspaceSize:设置可以分配给Metaspace的最大本机内存,默认是没有大小限制的。应用程序的Metaspace量取决于应用程序本身,其他正在运行的应用程序以及系统上可用的内存量
    -XX:MinMetaspaceFreeRatio:在GC后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
    -XX:MaxMetaspaceFreeRatio:在GC后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

    GC

    设置使用何种GC:

    • -XX:+UseSerialGC:设置串行收集器
    • -XX:+UseParallelGC:设置并行收集器,等价于-XX:+UseParallelOldGC
    • -XX:+UseParalledlOldGC:设置并行年老代收集器
    • -XX:+UseConcMarkSweepGC:设置CMS收集器
    • -XX:+UseG1GC:使用G1收集器

    一般都并行GC,常用参数

    • -XX:ParallelGCThreads=n:设置并行收集器年轻代收集方式为并行收集时,使用的CPU数,并行收集线程数
    • -XX:MaxGCPauseMillis=n:设置并行收集最大的暂停时间(如果到这个时间,GC依然没有回收完,也会停止回收)
    • -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比,公式为:1/(1+n)
    • -XX:+CMSIncrementalMode:设置为增量模式,适用于单CPU

    -XX:CMSFullGCsBeforeCompaction=5:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生碎片,使得运行效率降低。此值设置运行5次GC以后对内存空间进行压缩、整理。
    -XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但可以消除碎片

    打印GC回收过程的日志信息,不要用-XX:+UseGCLogFileRotation-XX:NumberOfGCLogFiles=5-XX:GCLogFileSize=20M,会丢失旧的日志文件,而且重启会覆盖当前日志文件。

    • -XX:+PrintGC
    • -XX:+PrintGCDetails:依赖于PrintGC
    • -XX:+PrintGCTimeStamps:依赖于PrintGC
    • -Xloggc:/home/GCEASY/gc-%t.log

    -XX:MAXTenuringThrehold:每个对象都有一个计数器,每次进行YGC时,都会 +1。通过此参数可以配置当计数器的值到达某个阈值时,对象就会从新生代移送至老年代。
    -XX:InitiatingHeapOccupancyPercent:启动并发GC周期时堆内存使用占比,G1用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比。值为 0 则表示一直执行GC循环,默认值45。
    -XX:G1HeapWastePercent:允许的浪费堆空间的占比,默认是10%,如果并发标记可回收的空间小于10%,则不会触发MixedGC。
    -XX:ConcGCThreads=n:并发垃圾收集器使用的线程数量,默认值随JVM运行的平台不同而不同
    -XX:G1MixedGCLiveThresholdPercent=65:混合垃圾回收周期中要包括的旧区域设置占用率阈值,默认占用率为65%
    -XX:G1MixedGCCountTarget=8:设置标记周期完成后,对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧区域执行混合垃圾回收的目标次数默认8次混合垃圾回收,混合回收的目标是要控制在此目标次数以内
    -XX:G1OldCSetRegionThresholdPercent=1:描述Mixed GC时,Old Region被加入到CSet中。默认情况下,G1只把10%的Old Region加入到CSet中。
    -XX:PrintTenuringDistribution:打印tenuring年龄信息,

    PrintHeapAtGC:一般都是false,即关闭。

    JMX

    -Djava.net.preferIPv4Stack=true
    -Dcom.sun.management.jmxremote
    -Djava.rmi.server.hostname={hostname}
    -Dcom.sun.management.jmxremote.port={port}
    -Dcom.sun.management.jmxremote.authenticate=false

    其他

    打印ClassLoader日志(所有类加载/卸载信息)
    -XX:+TraceClassLoading
    -XX:+TraceClassUnloading

    OOM时Dump内存
    -XX:+HeapDumpOnOutOfMemoryError
    -XX:HeapDumpPath=/data/heap-dump.hprof

    OOM时执行脚本(比如重启)
    -XX:OnOutOfMemoryError=/scripts/restart-myapp.sh

    禁止系统System.gc(),防止手动误触发FGC造成问题
    -XX:+DisableExplicitGC

    查看TLAB空间的使用情况
    -XX:+PrintTLAB

    打印JIT时间
    -XX:-CITime

    方法被编译时打印相关信息
    -XX:-PrintCompilation

    设置Integer缓存区间,默认值128,表示[-127, 128]
    -XX:AutoBoxCacheMax=256

    -XX:+PrintCompilation不能输出详细的信息,开启此参数把扩展的编译输出到hotspot.log文件。需解锁实验性功能。
    +LogCompilation

    由于与吞吐量关系密切,PS收集器也经常称为吞吐量优先收集器。-XX:+UseAdaptiveSizePolicy是一个开关参数,当这个参数打开之后,就不需要手工指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数,VM会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC Ergonomics)。使用PS收集器配合自适应调节策略,把内存管理的调优任务交给虚拟机去完成将是一个不错的选择。只需要把基本的内存数据设置好(如-Xmx设置最大堆),然后使用MaxGCPauseMillis参数(更关注最大停顿时间)或GCTimeRatio (更关注吞吐量)参数给虚拟机设立一个优化目标,那具体细节参数的调节工作就由虚拟机完成。自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别。

    新生代使用ParNew,老年代使用Serial Old
    -XX:+UseParNewGC(在Java8中已弃用,在Java9中已删除)

    最佳实践

    下面是一些缺省的写法
    JDK7

    JAVA_MEM_OPTS="-server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70"
    JAVA_DEBUG_OPTS="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/GCEASY/gc-%t.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/crashes/my-heap-dump.hprof -XX:OnOutOfMemoryError=/scripts/restart-myapp.sh"
    
    • 1
    • 2

    JDK8

    JAVA_MEM_OPTS="-server -Xmx2g -Xms2g -Xmn256m -XX:MetaspaceSize=256m -Xss1024m -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70"
    JAVA_DEBUG_OPTS="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/GCEASY/gc-%t.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/crashes/my-heap-dump.hprof -XX:OnOutOfMemoryError=/scripts/restart-myapp.sh"
    
    • 1
    • 2

    JDK8中已经支持G1。G1为用户的应用程序的提供一个低GC延时和大内存GC的解决方案,适用于大内存场景(官方推荐堆6G以上)。如果程序正在使用CMS或ParallelOld垃圾回收器,并具有以下一个或多个特征,则可以考虑升级为G1:

    • Full GC持续时间太长或太频繁
    • 对象分配率或年轻代升级老年代很频繁
    • 垃圾收集时间或压缩暂停(超过0.5至1秒)时间过长

    PS:如果正在使用CMS或ParallelOld收集器,并且程序没有遇到长时间的垃圾收集暂停,那么就不需要升级到G1。

    动态修改参数

    不是所有的参数都可以动态修改,查看哪些参数可动态修改:
    java -XX:+PrintFlagsFinal | grep manageable

    参考

  • 相关阅读:
    【Lua】脚本入门
    华为云Astro的前世今生:用7年时间革新低代码开发观念
    shardingsphere做了读写分离做了主从配置脱敏无效分析
    昇思MindSpore开源社区算力使能,快来SIG申请你的专属算力
    Scala下载和配置
    算法整理(五)
    2022,VSCode 前端插件推荐
    springboot 多数据源(如何连接两个数据库)
    信息化带来的制造业生产管理系统究竟有哪些作用呢?
    zookeeper集群
  • 原文地址:https://blog.csdn.net/lonelymanontheway/article/details/119542768