0
点赞
收藏
分享

微信扫一扫

面试必问之JVM常用参数


概述

面试必问系列。

参数分类

  1. 标准参数:​​-​​​,功能和输出的参数都很稳定,在将来的 JVM 版本中很可能不会改变。用​​java​​​或​​java -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)

查看当前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}

输出的每一行表示一个​​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}

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

bool BindCMSThreadToCPU                        = false                               {diagnostic}
bool C1PatchInvokeDynamic = true {C1 diagnostic}

堆、栈、元空间

​-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

​-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

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

永久代(PermGen,持久代)两个配置参数:
​​​-XX:PermSize​​​:设置永久代的初始大小,如果超出该大小,则会触发垃圾回收。此选项在JDK 8中已弃用,并由​​-XX:MetaspaceSize​​​选项取代。
​​​-XX:MaxPermSize​​​:设置永久代的最大值,默认是64M
对于永久代,如果动态生成很多class的话,就很可能出现<java.lang.OutOfMemoryError: PermGen space错误>,因为永久代空间配置有限。最典型的场景是,在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"

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"

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

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

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

动态修改参数

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

参考

  • ​​JVM常用参数以及命令​​
  • ​​动态修改JVM参数​​


举报

相关推荐

0 条评论