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 启用本地线程优先级
上面表格中黑体的三个参数代表着jvm中GC执行的三种方式,即串行、并行、并发
  • 串行(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左右。
一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。

默认值取决于平台:

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参数来禁掉System.gc()

辅助信息:

-XX:+PrintGC  打印GC信息  

输出形式:

[GC 118250K->113543K(130112K), 0.0094143 secs]
[Full GC 121376K->10414K(130112K), 0.0650971 secs]

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

输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 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)
new threshold 7即标识新的存活周期的阈值为7。

-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%的空余)。

 

经验&&规则

    1. 年轻代大小选择
      • 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择).在此种情况下,年轻代收集发生的频率也是最小的.同时,减少到达年老代的对象.
      • 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度.因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用.
      • 避免设置过小.当新生代设置过小时会导致:1.YGC次数更加频繁 2.可能导致YGC对象直接进入旧生代,如果此时旧生代满了,会触发FGC.
    2. 老年代大小选择
      1. 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得:
        并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。
      2. 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象.
    3. 较小堆引起的碎片问题
      因为年老代的并发收集器使用标记,清除算法,所以不会对堆进行压缩.当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象.但是,当堆空间较小时,运行一段时间以后,就会出现"碎片",如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记,清除方式进行回收.如果出现"碎片",可能需要进行如下配置:
      -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩.
      -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
    4. 用64位操作系统,Linux下64位的jdk比32位jdk要慢一些,但是吃得内存更多,吞吐量更大
    5. XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力
    6. 使用CMS的好处是用尽量少的新生代,经验值是128M-256M, 然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存, 大约20-80ms的应用程序停顿时间
    7. 系统停顿的时候可能是GC的问题也可能是程序的问题,多用jmap和jstack查看,或者killall -3 java,然后查看java控制台日志,能看出很多问题。(相关工具的使用方法将在后面的blog中介绍)
    8. 仔细了解自己的应用,如果用了缓存,那么年老代应该大一些,缓存的HashMap不应该无限制长,建议采用LRU算法的Map做缓存,LRUMap的最大长度也要根据实际情况设定。
    9. 采用并发回收时,年轻代小一点,年老代要大,因为年老大用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿
    10. 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

注:内存大小取决于使用服务器的资源配置

 

 

引用:

posted on 2021-05-22 18:43  曹伟雄  阅读(1799)  评论(0编辑  收藏  举报

导航