JVM——参数说明
前言
本文对常用 JVM 常用参数做了一个整理,但是参数的使用很复杂,本文仅仅提供常用参数的查阅,具体的使用还是需要根据具体的情况。
JVM 是一个开放的标准,谁可以来实现 JVM,这导致不同 JVM 实现的参数有所不同,本文基于 Hotspot 虚拟机。
JVM 参数很多,总体上可以分成三类:
-
-
:标准参数,比如-verbose:gc
这类表示标准实现,所有的虚拟机都需要实现这些参数的功能,且向后兼容; -
-X
:非标准参数,默认 JVM 会实现这些参数的功能,但是不保证所有的 JVM 实现都满足,且不保证向后兼容; -
-XX
:非 Stable 参数,这些参数在不同的 JVM 上会有不同的实现,这些参数不推荐在生成环境中使用,以后很有可能会被取消,需要慎重使用;
关于JVM选项的几点:
- 布尔型参数:-XX:+ 表示打开, -XX:- 表示关闭。(比如-XX:+PrintGCDetails);
- 数字型参数:通过 -XX:= 设定。数字可以是m/M(兆字节),k/K(千字节),g/G(G字节)。比如:32K表示32768字节;
- 字符行参数:通过 -XX:= 设定,通常用来指定一个文件,路径,或者一个命令列表。(比如-XX:HeapDumpPath=./java_pid.hprof)
关于JVM参数查看:
- java -help:该命令可以列出 java 应用启动时标准选项(不同的JVM实现是不同的);
- java -X:该命令可以列出不标准的参数(这是JVM的扩展特性)。
-
任何一个JVM参数的默认值可以通过java -XX:+PrintFlagsFinal -version |grep JVMParamName获取,例如:
java -XX:+PrintFlagsFinal -version |grep MetaspaceSize
标准参数
标准参数,所有的虚拟机都需要实现这些参数的功能,且向后兼容。可通过 java -help 命令来检索。
常用的参数说明:
- -server:设置jvm使server模式,特点是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境。在具有64位能力的jdk环境下将默认启用该模式,而忽略-client参数。
- -javaagent:指定jvm启动时装入java语言设备代理。
- -verbose:
- -verbose:class:输出jvm载入类的相关信息,当jvm报告说找不到类或者类冲突时可此进行诊断。
- -verbose:gc:输出每次GC的相关情况,当GC日志被保存为文件时,这个参数无效。
- -verbose:jni:输出native方法调用的相关情况,一般用于诊断jni调用错误信息。
非标准参数
非标准参数又称为扩展参数,非标准化的参数在将来的版本中可能会改变。所有的这类参数都以-X开始,并且可以用 java -X 来检索。
注意,不能保证所有参数都可以被检索出来,其中就没有-Xcomp。例如:
常用的参数说明:
- -Xms:设置JVM最小内存(比如:-Xms512m)。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
- -Xmx:设置JVM最大可用内存(比如:-Xmx512m)。
- -Xmn:设置年轻代的内存(比如:-Xmn200m)。此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是(eden+1 survivor space)不同的。
- -Xss:设置每个线程的堆栈大小(比如:-Xss128k)。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。
- -Xloggc:file:与-verbose:gc功能类似,只是将每次GC事件的相关情况记录到一个文件中,文件的位置最好在本地,以避免网络的潜在问题。若与verbose命令同时出现在命令行中,则以-Xloggc为准。
- -Xnoclassgc:表示关闭对类的垃圾回收。因为其阻止内存回收,所以可能会导致OutOfMemoryError错误,请谨慎使用。
非 Stable 参数
非Stable参数列表(以-XX作为前缀)在jvm中可能是不健壮的,SUN也不推荐使用,后续可能会在没有通知的情况下就直接取消了;
但是由于这些参数中的确有很多是对我们很有用的,比如我们经常会见到的-XX:PermSize、-XX:MaxPermSize等等;
下面我们将就Java HotSpot VM中 -XX: 的可配置参数列表进行描述,这些参数可以被松散的聚合成三类:
- 行为参数(Behavioral Options):用于改变jvm的一些基础行为;
- 性能调优(Performance Tuning):用于jvm的性能调优;
- 调试参数(Debugging Options):一般用于打开跟踪、打印、输出等jvm参数,用于显示jvm更加详细的信息;
由于sun官方文档中对各参数的描述也都非常少(大多只有一句话),而且大多涉及OS层面的东西,很难描述清楚,所以以下是挑选了一些我们开发中可能会用得比较多的配置项,
若需要查看所有参数列表,可以点击HotSpot VM Specific Options.查看原文;
行为参数:
参数及其默认值 | 描述 |
-XX:-DisableExplicitGC | 禁止调用System.gc();但jvm的gc仍然有效 |
-XX:+MaxFDLimit | 最大化文件描述符的数量限制 |
-XX:+ScavengeBeforeFullGC | 新生代GC优先于Full GC执行 |
-XX:+UseGCOverheadLimit | 在抛出OOM之前限制jvm耗费在GC上的时间比例 |
-XX:-UseConcMarkSweepGC | 对老生代采用并发标记交换算法进行GC |
-XX:-UseParallelGC | 启用并行GC |
-XX:-UseParallelOldGC | 对Full GC启用并行,当-XX:-UseParallelGC启用时该项自动启用 |
-XX:-UseSerialGC | 启用串行GC |
-XX:+UseThreadPriorities | 启用本地线程优先级 |
- 串行(SerialGC):是jvm的默认GC方式,一般适用于小型应用和单处理器,算法比较简单,GC效率也较高,但可能会给应用带来停顿;
- 并行(ParallelGC):是指GC运行时,对应用程序运行没有影响,GC和app两者的线程在并发执行,这样可以最大限度不影响app的运行;
- 并发(ConcMarkSweepGC):是指多个线程并发执行GC,一般适用于多处理器系统中,可以提高GC的效率,但算法复杂,系统消耗较大;
性能调优参数:
参数及其默认值 | 描述 |
-XX:LargePageSizeInBytes=4m | 设置用于Java堆的大页面尺寸 |
-XX:MaxHeapFreeRatio=70 | GC后java堆中空闲量占的最大比例 |
-XX:MaxNewSize=size | 新生成对象能占用内存的最大值 |
-XX:MaxPermSize=64m | 老生代对象能占用内存的最大值 |
-XX:MinHeapFreeRatio=40 | GC后java堆中空闲量占的最小比例 |
-XX:NewRatio=2 | 新生代内存容量与老生代内存容量的比例 |
-XX:NewSize=2.125m | 新生代对象生成时占用内存的默认值 |
-XX:ReservedCodeCacheSize=32m | 保留代码占用的内存容量 |
-XX:ThreadStackSize=512 | 设置线程栈大小,若为0则使用系统默认值 |
-XX:+UseLargePages | 使用大页面内存 |
我们在日常性能调优中基本上都会用到以上黑体的这几个属性。
调试参数:
参数及其默认值 | 描述 |
-XX:-CITime | 打印消耗在JIT编译的时间 |
-XX:ErrorFile=./hs_err_pid<pid>.log | 保存错误日志或者数据到文件中 |
-XX:-ExtendedDTraceProbes | 开启solaris特有的dtrace探针 |
-XX:HeapDumpPath=./java_pid<pid>.hprof | 指定导出堆信息时的路径或文件名 |
-XX:+HeapDumpOnOutOfMemoryError | 当首次遭遇OOM时导出此时堆中相关信息 |
-XX:OnError="<cmd args>;<cmd args>" | 出现致命ERROR之后运行自定义命令 |
-XX:OnOutOfMemoryError="<cmd args>;<cmd args>" | 当首次遭遇OOM时执行自定义命令 |
-XX:-PrintClassHistogram | 遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同 |
-XX:-PrintConcurrentLocks | 遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同 |
-XX:-PrintCommandLineFlags | 打印在命令行中出现过的标记 |
-XX:-PrintCompilation | 当一个方法被编译时打印相关信息 |
-XX:-PrintGC | 每次GC时打印相关信息 |
-XX:-PrintGC Details | 每次GC时打印详细信息 |
-XX:-PrintGCTimeStamps | 打印每次GC的时间戳 |
-XX:-TraceClassLoading | 跟踪类的加载信息 |
-XX:-TraceClassLoadingPreorder | 跟踪被引用到的所有类的加载信息 |
-XX:-TraceClassResolution | 跟踪常量池 |
-XX:-TraceClassUnloading | 跟踪类的卸载信息 |
-XX:-TraceLoaderConstraints | 跟踪类加载器约束的相关信息 |
当系统出现问题的时候,又不能使用外部跟踪工具(比如JProfiler……)的情况下,以上的这些参数就会发挥重大作用了,比如dump堆信息、打印并发锁……
参数汇总
不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM、GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率。
但是调整GC是以个极为复杂的过程,由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要cup个数,内存不同),
所以使用的GC种类也会不同(如何选择见GC种类及如何选择)。本文将注重介绍JVM、GC的一些重要参数的设置来提高系统的性能。
JVM内存组成及GC相关内容请见文章:JVM内存组成 GC策略&内存申请。
常用JVM参数:
参数名称 | 含义 | 默认值 | |
-Xms | 初始堆大小 | 物理内存的1/64(<1GB) | 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制. |
-Xmx | 最大堆大小 | 物理内存的1/4(<1GB) | 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制 |
-Xmn | 年轻代大小(1.4or lator) | 注意:此处大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小. 增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8 |
|
-XX:NewSize | 设置年轻代大小(for 1.3/1.4) | ||
-XX:MaxNewSize | 年轻代最大值(for 1.3/1.4) | ||
-XX:PermSize | 设置持久代(perm gen)初始值 | 物理内存的1/64 | 在JDK1.8以后面的版本,使用元空间(-XX:MetaspaceSize)来代替永久代 |
-XX:MaxPermSize | 设置持久代最大值 | 物理内存的1/4 | 在JDK1.8以后面的版本,使用元空间(-XX:MaxMetaspaceSize)来代替永久代 |
-Xss |
每个线程的堆栈大小 -Xss1024k等同于: -XX:ThreadStackSize=1024k |
JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。 默认值取决于平台: Linux/ARM (32-bit): 320 KB Linux/i386 (32-bit): 320 KB Linux/x64 (64-bit): 1024 KB OS X (64-bit): 1024 KB Oracle Solaris/i386 (32-bit): 320 KB Oracle Solaris/x64 (64-bit): 1024 KB |
|
-XX:ThreadStackSize | 设置线程堆栈大小 | (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.] | |
-XX:NewRatio | 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代) | -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。 |
|
-XX:SurvivorRatio | Eden区与Survivor区的大小比值 | 默认为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 | |
-XX:+UseLargePages | 使用大页面内存 | ||
-XX:LargePageSizeInBytes | 设置用于Java堆的大页面尺寸 | =128m,内存页的大小不可设置过大, 会影响Perm的大小 | |
-XX:+UseFastAccessorMethods | 原始类型的快速优化 | 1.7以后不建议使用,1.6之前默认打开 | |
-XX:+UseFastEmptyMethods | 优化空方法 | 1.7以后不建议使用,1.6之前默认打开 | |
-XX:MaxTenuringThreshold | 对象存在于新生代所能经历Minor GC的最大次数 | 并行(吞吐量)收集器的默认值为15,而CMS收集器的默认值为6 | 如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率 |
-XX:PretenureSizeThreshold | 超出该大小的对象直接在老年代分配 | 0 | 单位字节 新生代采用Parallel Scavenge GC时无效 另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象. |
-XX:+AggressiveOpts | 加快编译 | ||
-XX:+UseBiasedLocking | 锁机制的性能改善 | ||
-Xnoclassgc | 禁用对类的垃圾回收 | 禁用类的垃圾收集(GC)。这可以节省一些GC时间,从而缩短应用程序运行期间的中断。当您在启动时指定-Xnoclassgc时,应用程序中的类对象将在GC期间保持不变,并且始终被视为活动的。这会导致更多的内存被永久占用,如果不小心使用,会引发内存不足异常。 | |
-XX:SoftRefLRUPolicyMSPerMB | 每兆堆空闲空间中SoftReference的存活时间 | 1s | 每1M空闲空间可保持的SoftReference对象生存的时长(单位ms)。这个参数就是一个常量,默认值1000 |
-XX:TLABWasteTargetPercent | TLAB占eden区的百分比 | 1% | |
-XX:+CollectGen0First | FullGC时是否先YGC | false | |
-XX:+DisableExplicitGC | 关闭System.gc() | 这个参数需要严格的测试 | |
-XX:MaxMetaspaceSize | 元空间的最大值 | 没有限制 | jdk1.8 |
-XX:MetaspaceSize | 设置触发元空间Full GC的阈值 | 21M(64位服务器) |
jdk1.8,指Metaspace扩容时触发FullGC的初始化阈值,也是最小的阈值。 Metaspace使用的是本地内存,而不是堆内存。 |
-XX:MaxHeapFreeRatio | GC后java堆中空闲量空间的最大占比 | 70% | 如果可用堆空间高于此值,则堆将被缩小 |
-XX:MinHeapFreeRatio | GC后java堆中空闲量空间的最小占比 | 40% | 如果可用堆空间低于此值,则堆将被扩展 |
-XX:MaxDirectMemorySize | 最大堆外内存 | 64M | 当Direct ByteBuffer分配的堆外内存到达指定大小后,即触发Full GC。注意该值是有上限的,默认是64M,最大为sun.misc.VM.maxDirectMemory() |
并行收集器相关参数:
-XX:+UseParallelGC | 使用parallel 和 parallel old 收集器 |
JDK1.8默认就是以下组合-XX:+UseParallelGC 新生代使用ParallelScavenge,老年代使用ParallelOld |
|
-XX:+UseParNewGC | 设置年轻代为ParNew收集器(并行收集器) | 禁用状态 | 设置该-XX:+UseConcMarkSweepGC 选项时,它将自动启用。 |
-XX:ParallelGCThreads | 并行收集器的线程数 | 此值最好配置与处理器数目相等 同样适用于CMS | |
-XX:+UseParallelOldGC | 老年代垃圾收集方式为并行收集(Parallel Compacting) | 这个是JAVA 6出现的参数选项 | |
-XX:MaxGCPauseMillis | 每次年轻代垃圾回收的最长时间(最大暂停时间) | 200ms |
VM将调整Java堆大小和其他与GC相关的参数,以使GC引起的暂停时间短于设定的毫秒,尽可能地保证内存回收花费时间不超过设定值。 请注意,这可能会导致VM降低整体吞吐量(吞吐量=运行用户代码时间/VM总运行时间),并且在某些情况下,VM将无法达到所需的暂停时间目标。 默认情况下,VM没有暂停时间目标值。GC的暂停时间主要取决于堆中实时数据的数量与实时数据量。 该参数应谨慎使用。太小的值将导致系统花费过多的时间进行垃圾回收。原因是为满足最大暂停时间,VM将设置更小的堆,以存储相对少量的对象,来提升回收速率,会导致更高频率的GC。 |
-XX:+UseAdaptiveSizePolicy | 自动选择年轻代区大小和相应的Survivor区比例 | 启用 | 设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开. |
-XX:GCTimeRatio | 垃圾收集时间占总时间的比率 |
表示希望在GC花费不超过应用程序执行时间的1/(1+n),n为大于0小于100的整数。 换句话说,此参数的值表示运行用户代码时间是GC运行时间的n倍。 举个官方的例子,参数设置为19,那么GC最大花费时间的比率=1/(1+19)=5%,程序每运行100分钟,允许GC停顿共5分钟,其吞吐量=1-GC最大花费时间比率=95% 默认情况下,VM设置此值为99,运行用户代码时间是GC停顿时间的99倍,即GC最大花费时间比率为1% |
|
-XX:+ScavengeBeforeFullGC | Full GC前调用YGC | true | Do young generation GC prior to a full GC. (Introduced in 1.4.1.) |
CMS相关参数:
-XX:+UseConcMarkSweepGC | 使用CMS垃圾收集器 | 使用parNew 和 CMS 收集器(启用此选项后,会自动设置-XX:+UseParNewGC选项)。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代大小最好用-Xmn设置.??? | |
-XX:+AggressiveHeap | 试图是使用大量的物理内存 长时间大内存使用的优化,能检查计算资源(内存, 处理器数量) 至少需要256MB内存 大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提升) |
||
-XX:+CMSScavengeBeforeRemark | 在FullGC前启动一次MinorGC | 目的在于减少老年代对年轻代的引用,降低CMSGC的标记阶段时的开销 | |
-XX:CMSFullGCsBeforeCompaction | 多少次fullGC后进行压缩一次(碎片整理) | 0 | 由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理. |
-XX:+CMSParallelInitialMarkEnabled | 使用多线程进行初始标记,降低标记停顿 | 默认单线程 | 可以减少STW |
-XX:+CMSParallelRemarkEnabled | 使用多线程进行重新标记,降低标记停顿 | 默认单线程 | 可以减少STW |
-XX+UseCMSCompactAtFullCollection | 在FULL GC的时候,开启内存碎片合并整理过程 | CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。 可能会影响性能,但是可以消除碎片 |
|
-XX:CMSInitiatingOccupancyFraction=70 | 使用cms作为垃圾回收,使用70%后开始CMS收集 | 92 | 为了保证不出现promotion failed(见下面介绍)错误,该值的设置需要满足以下公式CMSInitiatingOccupancyFraction计算公式 |
-XX:+UseCMSInitiatingOccupancyOnly | 这个参数搭配-XX:CMSInitiatingOccupancyFraction使用,表示不是要一直使用它的比例触发FullGC,如果设置则只会在第一次FullGC的时候使用-XX:CMSInitiatingOccupancyFraction的值,之后会进行自动调整。 | ||
-XX:CMSInitiatingPermOccupancyFraction | 设置Perm Gen使用到达多少比率时触发 | 92 | |
-XX:+CMSIncrementalMode | 设置为增量模式 | 用于单CPU情况 | |
-XX:+CMSClassUnloadingEnabled | |||
-XX:+ExplicitGCInvokesConcurrent | 改变System.gc()的行为,让其从full gc –> CMS GC |
如果系统使用堆外内存,比如用到了Netty的DirectByteBuffer类,那么当想回收堆外内存的时候,需要调用system.gc(),而这个方法将进行full gc,整个应用将会停顿,如果是使用CMS垃圾收集器,那么可以设置此参数。 注意:设置了ExplicitGCInvokesConcurrent,那就不要设置DisableExplicitGC参数来禁掉 |
辅助信息:
-XX:+PrintGC | 打印GC信息 |
输出形式: [GC 118250K->113543K(130112K), 0.0094143 secs] |
|
-XX:+PrintGCDetails | 打印GC详细信息 |
输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] |
|
-XX:+PrintGCTimeStamps | 打印GC过程中具体的时间戳 | ||
-XX:+PrintGC:PrintGCTimeStamps | 可与-XX:+PrintGC -XX:+PrintGCDetails混合使用 输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs] |
||
-XX:+PrintGCApplicationStoppedTime | 打印垃圾回收期间程序暂停的时间 | 输出形式:Total time for which application threads were stopped: 0.0468229 seconds | |
-XX:+PrintGCApplicationConcurrentTime | 打印每次垃圾回收前,程序未中断的执行时间 | 输出形式:Application time: 0.5291524 seconds | |
-XX:+PrintHeapAtGC | 打印GC前后的详细堆栈信息 | ||
-Xloggc:filename | 把相关日志信息记录到文件以便分析 | ||
-XX:+PrintClassHistogram |
遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同 | ||
-XX:+PrintTLAB | 查看TLAB空间的使用情况 | ||
-XX:+PrintTenuringDistribution |
查看对像存在于新生代所经历 Minor GC次数的阈值 |
Desired survivor size 1048576 bytes, new threshold 7 (max 15) |
|
-XX:PrintReferenceGC |
打印软引用、弱引用、虚引用和Finallize队列 |
||
-XX:ErrorFile | 指定发生不可恢复的错误时将错误数据写入的路径和文件名 |
默认情况下,此文件在当前工作目录中创建,并命名为hs_err_pid.log,其中pid是导致错误的进程的标识符。 以下示例显示了如何将错误日志设置为/var/log/java/java_error.log: -XX:ErrorFile = / var / log / java / java_error.log |
|
-XX:OnOutOfMemoryError | 发生OutOfMemoryError第一次引发异常时运行的自定义命令或一系列用分号分隔的命令。 | -XX:OnOutOfMemoryError="C:\Program Files\Java\jdk1.8.0_152\bin\jconsole.exe" | |
-XX:+HeapDumpOnOutOfMemoryError | 开启堆转储 | 禁用 | java.lang.OutOfMemoryError引发异常时,使用堆分析器(HPROF)启用将Java堆转储到当前目录中的文件的功能。您可以使用该-XX:HeapDumpPath选项显式设置堆转储文件的路径和名称。 |
-XX:HeapDumpPath | 设置堆转储的路径和文件名 | 设置-XX:+HeapDumpOnOutOfMemoryError选项时,设置用于写入由堆分析器(HPROF)提供的堆转储的路径和文件名。默认情况下,在当前工作目录中创建该文件,并将其命名为java_pid.hprof,其中pid是导致错误的进程的标识符。 |
GC性能方面的考虑
对于GC的性能主要有2个方面的指标:吞吐量throughput(工作时间不算gc的时间占总的时间比)和暂停pause(gc发生时app对外显示的无法响应)。
1. Total Heap
默认情况下,vm会增加/减少heap大小以维持free space在整个vm中占的比例,这个比例由MinHeapFreeRatio和MaxHeapFreeRatio指定。
一般而言,server端的app会有以下规则:
- 对vm分配尽可能多的memory;
- 将Xms和Xmx设为一样的值。如果虚拟机启动时设置使用的内存比较小,这个时候又需要初始化很多对象,虚拟机就必须重复地增加内存。
- 处理器核数增加,内存也跟着增大。
2. The Young Generation
另外一个对于app流畅性运行影响的因素是young generation的大小。young generation越大,minor collection越少;但是在固定heap size情况下,更大的young generation就意味着小的tenured generation,就意味着更多的major collection(major collection会引发minor collection)。
NewRatio反映的是young和tenured generation的大小比例。NewSize和MaxNewSize反映的是young generation大小的下限和上限,将这两个值设为一样就固定了young generation的大小(同Xms和Xmx设为一样)。
如果希望,SurvivorRatio也可以优化survivor的大小,不过这对于性能的影响不是很大。SurvivorRatio是eden和survior大小比例。
一般而言,server端的app会有以下规则:
- 首先决定能分配给vm的最大的heap size,然后设定最佳的young generation的大小;
- 如果heap size固定后,增加young generation的大小意味着减小tenured generation大小。让tenured generation在任何时候够大,能够容纳所有live的data(留10%-20%的空余)。
经验&&规则
- 年轻代大小选择
- 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择).在此种情况下,年轻代收集发生的频率也是最小的.同时,减少到达年老代的对象.
- 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度.因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用.
- 避免设置过小.当新生代设置过小时会导致:1.YGC次数更加频繁 2.可能导致YGC对象直接进入旧生代,如果此时旧生代满了,会触发FGC.
- 老年代大小选择
- 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得:
并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。 - 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象.
- 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得:
- 较小堆引起的碎片问题
因为年老代的并发收集器使用标记,清除算法,所以不会对堆进行压缩.当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象.但是,当堆空间较小时,运行一段时间以后,就会出现"碎片",如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记,清除方式进行回收.如果出现"碎片",可能需要进行如下配置:
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩.
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩 - 用64位操作系统,Linux下64位的jdk比32位jdk要慢一些,但是吃得内存更多,吞吐量更大
- XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力
- 使用CMS的好处是用尽量少的新生代,经验值是128M-256M, 然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存, 大约20-80ms的应用程序停顿时间
- 系统停顿的时候可能是GC的问题也可能是程序的问题,多用jmap和jstack查看,或者killall -3 java,然后查看java控制台日志,能看出很多问题。(相关工具的使用方法将在后面的blog中介绍)
- 仔细了解自己的应用,如果用了缓存,那么年老代应该大一些,缓存的HashMap不应该无限制长,建议采用LRU算法的Map做缓存,LRUMap的最大长度也要根据实际情况设定。
- 采用并发回收时,年轻代小一点,年老代要大,因为年老大用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿
- JVM参数的设置(特别是 –Xmx –Xms –Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold等参数的设置没有一个固定的公式,需要根据PV old区实际数据 YGC次数等多方面来衡量。为了避免promotion faild可能会导致xmn设置偏小,也意味着YGC的次数会增多,处理并发访问的能力下降等问题。每个参数的调整都需要经过详细的性能测试,才能找到特定应用的最佳配置。
本人生产使用配置
- CMS
-Xms1g -Xmx1g -Xmn512m -Xss256K -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:SoftRefLRUPolicyMSPerMB=0
-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=8 -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSScavengeBeforeRemark -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSParallelInitialMarkEnabled -XX:+CMSParallelRemarkEnabled
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$file_path/logs/sas/sas.memory.dump -Xloggc:$file_path/logs/sas/sas.gc.log
- G1
-Xms1g -Xmx1g -Xmn512m -Xss256K -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:SoftRefLRUPolicyMSPerMB=0
-XX:+UseG1GC -XX:MaxGCPauseMillis=400
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$file_path/logs/sas/sas.memory.dump -Xloggc:$file_path/logs/sas/sas.gc.log
注:内存大小取决于使用服务器的资源配置
引用: