JVM调优参数汇总
一、JVM升级:
① Sun公司的HotSpot;
② BEA公司的JRockit;
③ IBM公司的J9 JVM;
在JDK1.7及其以前我们所使用的都是Sun公司的HotSpot,但由于Sun公司和BEA公司都被oracle收购,jdk1.8将采用Sun公司的HotSpot和BEA公司的JRockit两个JVM中精华形成jdk1.8的JVM。
1.1对比:
JDK 1.7 及以往的 JDK 版本中,Java 类信息、常量池、静态变量都存储在 Perm(永久代)里。类的元数据和静态变量在类加载的时候分配到 Perm,当类被卸载的时候垃圾收集器从 Perm 处理掉类的元数据和静态变量。当然常量池的东西也会在 Perm 垃圾收集的时候进行处理。
JDK 1.8 的对 JVM 架构的改造将类元数据放到本地内存中,另外,将常量池和静态变量放到 Java 堆里。HotSpot VM 将会为类的元数据明确分配和释放本地内存。在这种架构下,类元信息就突破了原来 -XX:MaxPermSize 的限制,现在可以使用更多的本地内存。这样就从一定程度上解决了原来在运行时生成大量类的造成经常 Full GC 问题,如运行时使用反射、代理等。
1.2注意:
如果服务器内存足够,升级到 JDK 1.8 修改 JVM 参数最简单的办法就是将 -XX:PermSize 和 -XX:MaxPermSize 参数替换为 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize
1.8中-XX:PermSize 和 -XX:MaxPermSize 已经失效,取而代之的是一个新的区域 —— Metaspace(元数据区)。
使用JDK1.8以及之后的版本,不会再碰上“java.lang.OutOfMemoryError: PermGen space”这个错误了。
1.3优势理解:
permSize:原来的jar包及你自己项目的class存放的内存空间,这部分空间是固定的,启动参数里面-permSize确定,如果你的jar包很多,经常会遇到permSize溢出,且每个项目都会占用自己的permGen空间
改成metaSpaces,各个项目会共享同样的class内存空间,比如两个项目都用了fast-json开源包,在mentaSpaces里面只存一份class,提高内存利用率,且更利于垃圾回收
1.4区别
元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制
1.5参数来指定元空间的大小
-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。
除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
二、 JVM启动参数共分为三类:
1、标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容。例如:-verbose:class(输出jvm载入类的相关信息,当jvm报告说找不到类或者类冲突时可此进行诊断);-verbose:gc(输出每次GC的相关情况);-verbose:jni(输出native方法调用的相关情况,一般用于诊断jni调用错误信息)。
2、非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容。例如:-Xms512m;-Xmx512m;-Xmn200m;-Xss128k)。
3、非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用。例如:-XX:PermSize=64m;-XX:MaxPermSize=512m。
三、汇总
1、JVM-调优参数-JDK1.7
基本选项(选取部分)
-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:LargePageSizeInBytes
|
内存页的大小不可设置过大, 会影响Perm的大小
|
因为每页size变大了,导致JVM在计算Heap内部分区(perm, new, old)内存占用比例时,会出现超出正常值的划分。最坏情况下是,某个区会多占用一个页的大小。不过后续jvm版本也在调整这个策略。 一般情况,不建议将页size调得太大,4-64M,是可以接受的(默认是4M)。 另外,网上有很多GC调优的文章内容中都有提到 LargePageSizeInBytes,但未提任何OS限制。在OS不支持的情况下,设置这个参数,这个参数将仅仅是个摆设。
|
|
-XX:+UseFastAccessorMethods
|
原始类型的快速优化
|
||
-XX:+DisableExplicitGC
|
关闭System.gc()
|
这个参数需要严格的测试
|
|
-XX:MaxTenuringThreshold
|
垃圾最大年龄
|
如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率 该参数只有在串行GC时才有效.
|
|
-XX:+AggressiveOpts
|
加快编译
|
||
-XX:+UseBiasedLocking
|
锁机制的性能改善
|
||
-Xnoclassgc
|
禁用垃圾回收
|
||
-XX:SoftRefLRUPolicyMSPerMB
|
每兆堆空闲空间中SoftReference的存活时间
|
1s
|
softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap
|
-XX:PretenureSizeThreshold
|
对象超过多大是直接在旧生代分配
|
0
|
单位字节 新生代采用Parallel Scavenge GC时无效 另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象.
|
-XX:TLABWasteTargetPercent
|
TLAB占eden区的百分比
|
1%
|
|
-XX:+CollectGen0First
|
FullGC时是否先YGC
|
false
|
|
-XX: -DisableExplicitGC
|
默认情况下只要调用System.gc()就可以开启.使用-XX:+DisableExplicitGC关闭调用System.gc(),==注意,当内存不足时,JVM依然会产生垃圾回收动作==
|
并行收集器相关参数
-XX:+UseParallelGC
|
Full GC采用parallel MSC (此项待验证)
|
选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.(此项待验证)
|
|
-XX:+UseParNewGC
|
设置年轻代为并行收集
|
可与CMS收集同时使用 JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值
|
|
-XX:ParallelGCThreads
|
并行收集器的线程数
|
此值最好配置与处理器数目相等 同样适用于CMS
|
|
-XX:+UseParallelOldGC
|
年老代垃圾收集方式为并行收集(Parallel Compacting)
|
这个是JAVA 6出现的参数选项
|
|
-XX:MaxGCPauseMillis
|
每次年轻代垃圾回收的最长时间(最大暂停时间)
|
如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值.
|
|
-XX:+UseAdaptiveSizePolicy
|
自动选择年轻代区大小和相应的Survivor区比例
|
设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开.
|
|
-XX:GCTimeRatio
|
设置垃圾回收时间占程序运行时间的百分比
|
公式为1/(1+n)
|
|
-XX:+ScavengeBeforeFullGC
|
Full GC前调用YGC
|
true
|
Do young generation GC prior to a full GC. (Introduced in 1.4.1.)
|
CMS相关参数
-XX:+UseConcMarkSweepGC
|
使用CMS内存收集
|
||
-XX:+AggressiveHeap
|
试图是使用大量的物理内存 长时间大内存使用的优化,能检查计算资源(内存, 处理器数量) 至少需要256MB内存 大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提升)
|
||
-XX:CMSFullGCsBeforeCompaction
|
多少次后进行内存压缩
|
由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生”碎片”,使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理.
|
|
-XX:+CMSParallelRemarkEnabled
|
降低标记停顿
|
||
-XX+UseCMSCompactAtFullCollection
|
在FULL GC的时候, 对年老代的压缩
|
CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。 可能会影响性能,但是可以消除碎片
|
|
-XX:+UseCMSInitiatingOccupancyOnly
|
使用手动定义初始化定义开始CMS收集
|
禁止hostspot自行触发CMS GC
|
|
-XX:CMSInitiatingOccupancyFraction=70
|
使用cms作为垃圾回收 使用70%后开始CMS收集
|
92
|
和上面的配合使用
|
-XX:CMSInitiatingPermOccupancyFraction
|
设置Perm Gen使用到达多少比率时触发
|
92
|
|
-XX:+CMSIncrementalMode
|
设置为增量模式
|
用于单CPU情况
|
|
-XX:+CMSClassUnloadingEnabled
|
垃圾第一(G1),垃圾回收选项
选项和默认值
|
描述
|
-XX:+UseG1GC
|
使用垃圾优先(G1)回收器
|
-XX:MaxGCPauseMillis=n
|
设置回收器的最大停顿时间,这是一个比较简单的目标,JVM将尽最大努力去实现它
|
-XX:InitiatingHeapOccupancyPercent=n
|
在并行GC模式下的堆占用率,它影响的是全部运行并行GC的回收器,默认值是45
|
-XX:NewRatio=n
|
老年代和新生代的空间比例,默认值是2,计算公式是NewRatio=老年代/新生代
|
-XX:SurvivorRatio=n
|
对象出生地(eden)和幸存区(s0/s1)的的空间比例,默认值是8,计算公式是SurvivorRation=eden/(s0+s1)
|
-XX:MaxTenuringThreshold=n
|
最大临界值,默认是15
|
-XX: ParallelGCThreads=n
|
设置垃圾回收器并行阶段中使用的线程数,默认值跟平台相关
|
-XX:ConcGCThreads=n
|
并行垃圾回收器的线程数量,默认值跟平台有关
|
-XX:G1ReservePercent=n
|
设置堆的临时上限,以防止因堆扩大失败而导致的错误。默认值是10
|
-XX:G1HeapRegionSize=n
|
使用G1的Java堆细分为均匀大小的区域,这个选项是设置单个区域的大小,这个选项的默认值是基于堆大小进行效率划分的值来决定(The default value of this parameter is determined ergonomically based upon heap size)。最小值是1Mb并且最大值是32Mb.
|
性能参数
选项和默认值
|
描述
|
-XX:+AggressiveOpts
|
打开点性能编译器优化,在未来版本中可能是默认打开(版本5.0更新6中声明)
|
-XX:CompileThreshold=10000
|
在编译前的方法调用数[-client:1500]
|
-XX:LargePageSizeInBytes=4m
|
设置java堆的大页容量(版本1.4.0更新1中声明)[amd64:2m]
|
-XX:MaxHeapFreeRatio=70
|
GC过后堆的最大空闲空间比例,避免过于压缩
|
-XX:MaxNewSize=size
|
新生代的最大容量,版本1.4后,通过NewRatio函数来计算(1.3.1 Sparc: 32m; 1.3.1 x86: 2.5m)
|
-XX:MaxPermSize=64M
|
老年代的最大容量,[5.0以后,64位的VM都扩容了30%,1.4 amd64:96m,1.3.1 -client:32m]
|
-XX:MinHeapFreeRatio=40
|
GC过后堆的最小空闲空间比例,避免过于膨胀
|
-XX:NewRatio=2
|
老年代和新生代的空间比例,计算公式:NewRatio=老年代/新生代。[Sparc -client:8;x86 -server:8;x86 -client:12] -client:4(1.3)8(1.3.1+),x86:12
|
-XX:NewSize=2m
|
新生代的默认容量大小[5.0以后:64位VM扩张30%;x86:1m;x86,5.0之前:640k]
|
-XX:ReservedCodeCacheSize=32m
|
保留代码缓存大小–代码缓存容量的最大值[Solaris 64位,amd64和 x86 -server:2048m;版本5.0_06以后,Solaris 64位和amd64:1024m]
|
-XX:SurvivorRatio=8
|
对象出生地(eden)和幸存区(s0/s1)的空间比例,计算公式:SurvivorRatio=eden/(s0+s1)。[Solaris amd64:6;1.3.1版的Sparc:25;其他Solaris平台,5.0以前:32]
|
-XX:TargetSurvivorRatio=50
|
清理过后幸存区的期望空间大小
|
-XX:ThreadStackSize=512
|
线程栈大小.(0表示使用默认值)[Sparc:512;Solaris x86:320(5.0以前的256系列);Sparc 64位:1024;Linux amd64:1024(5.0以前是0);其他都是0]
|
-XX:+UseBiasedLocking
|
使用偏向锁(版本5.0更新6中声明)[5.0 false]
|
-XX:+UseFastAccessorMethods
|
使用Get<基本类型>字段的优化版本
|
-XX:-UselSM
|
使用私有共享内存[非Solaris平台不允许使用]
|
-XX:+UseLargePages
|
使用大页内存(版本5.0更新5中声明)
|
-XX:+UseMPSS
|
使用多页大小支持W/4MB页的堆,不要使用ISM,因为这取代了ISM的需要。
|
-XX:+UseStringCache
|
启用对常用分配字符串的缓存
|
-XX:AllocatePrefetchLines=1
|
使用JIT编译代码生成的预取指令在最后一个对象分配后加载的缓存行数。如果最后一个分配对象是实例,则默认值是1,是数组则为3
|
-XX:AllocatePrefetchStyle=1
|
生成预取指令的代码样式:0,没有预取指令生成;1,在每次分配之后执行预取指令; 2,当预取指令执行的时候,使用TLAB分配水印指针(use TLAB allocation watermark pointer to gate )
|
-XX:+UseCompressedStrings
|
使用字符串的字节数组来表示ASCII
|
-XX:+OptimizeStringConcat
|
尽可能的优化字符串的相关操作
|
调试选项
选项和默认值
|
描述
|
-XX:-CITime
|
打印JIT编译器的时间消耗
|
-XX:ErrorFile=./hs_err_pid.log
|
如果有错误产生,则把错误数据保存在对应文件中
|
-XX:-ExtendedDTraceProbes
|
打开影响性能追踪检测
|
-XX:HeapDumpPath=./java_pid/hprof
|
设置导出堆大小的目录或文件名的路径
|
-XX:-HeapDumpOnOutOfMemoryError
|
当产生内存溢出的时候导出堆信息到文件中
|
-XX: OnError=”;”
|
当发生致命错误的时候运行用户定义的命令
|
-XX: OnOoutOfMemoryError=”;”
|
当产生内存溢出的时候运行用户定义的命令
|
-XX: -PrintClassHistogram
|
使用Ctrl-Break打断的时候打印类实例的直方图
|
-XX: -PrintConcurrentLocks
|
使用Ctrl-Break打断的时候打印java.util.concurrent.Lock信息
|
-XX: -PrintCommandLineFlags
|
打印随命令行而来的标识
|
-XX: -PrintCompilation
|
打印方法被编译时的信息
|
-XX: -PrintGC
|
打印进行垃圾回收时的信息
|
-XX: -PrintGCDetails
|
打印进行垃圾回收时的详细信息
|
-XX: -PrintGCTimeStamps
|
打印进行垃圾回收时的时间戳
|
-XX: -PrintTenuringDistribution
|
打印期限年龄信息(Print tenuring age information)
|
-XX: -PrintAdaptiveSizePolicy
|
打印自适应生成大小的信息
|
-XX:-TraceClassLoading
|
追踪类加载信息
|
-XX:-TraceClassLoadingPreorder
|
当按引用顺序加载的时候追踪所有类
|
-XX:-TraceClassResolution
|
追踪常量池分解
|
-XX:-TraceClassUnloading
|
追踪卸载类
|
-XX:-TraceLoaderConstraints
|
追踪加载器约束的记录
|
-XX:+PerfDataSaveToFile
|
在退出时保存jvmstat的二进制数据
|
-XX: ParallelGCThreads=n
|
设置新生代和老年代中的并行回收器的垃圾回收线程数量,默认值跟平台有关
|
-XX:+UserCompressedOops
|
开启压缩指针的使用(对象引用使用32位的偏移量来表示,而不是64位的指针)来优化64位的性能,使得java堆容量小于32gb(Enables the use of compressed pointers (object references represented as 32 bit offsets instead of 64-bit pointers) for optimized 64-bit performance with Java heap sizes less than 32gb)
|
-XX:+AlwarysPreTouch
|
在JVM初始化区间预触摸Java堆,在初始化区间,堆的每一页都进行了类似的调零,相当于在程序运行时进行增量变化
|
-XX:AllocatePrefetchDistance=n
|
设置对象分配的预取间隔。新对象写入时所用的内存空间都是根据这个值从缓存中来分配,除了最后分配的对象。每个java线程都有自己的分配点。这个选项的默认值跟平台有关
|
-XX:InlineSmallCode=n
|
仅在方法生成的本地字节码大小小于此之前,内联先前编译的方法(Inline a previously compiled method only if its generated native code size is less than this)。默认值跟平台有关
|
-XX:MaxInlineSize=35
|
内联方法的最大字节码容量
|
-XX:FreqInlineSize=n
|
内联方法被频繁执行时的最大字节码容量
|
-XX:LoopUnrooLimit=n
|
在Server模式下的编译器展开循环体的节点要小于这个选项的值,这个选项的值,在Server模式下的编译器中是一个函数,而不是一个具体值,这个参数的默认跟平台有关。
|
-XX:InitialTenuringThreshold=7
|
设置年轻代中使用自适应GC大小的并行收集器的初始临界值(threshold),这个值是一个对象在被推进老年代之前,在年轻代中的幸存次数。
|
-XX:MaxTenuringThreshold=n
|
设置使用自定义GC大小的最大临界值,这个选项的最大值是15,并行收集器的默认值是15而CMS的默认值是4
|
-Xloggc:
|
输出GC详细日志到指定文件,具体详细输出内容由GC标签参数决定
|
-XX:-UseGCLogFileRotation
|
打开循环输出GC日志,同时需要-Xloggc支持
|
-XX:NumberOfGClogFiles=1
|
设置循环输出GC日志的文件名,必须有一个以上,循环日志文件的命名需遵从以下规则:.0,.1,…,.n-1。
|
-XX:GCLogFileSize=8K
|
日志文件循环的条件,日志文件的大小,必须大于等于8k
|
2、JVM-调优参数-JDK1.8
标准参数
选项和默认值
|
描述
|
-d32
|
使用 32 位数据模型 (如果可用)
|
-d64
|
使用 64 位数据模型 (如果可用)
|
-server
|
选择 “server” VM,默认 VM 是 server.
|
-cp
|
<目录和 zip/jar 文件的类搜索路径>
|
-classpath
|
<目录和 zip/jar 文件的类搜索路径>,用 ‘;’ 分隔的目录, JAR 档案和 ZIP档案列表, 用于搜索类文件。
|
-D<名称>=<值>
|
设置系统属性
|
-verbose:[class/gc/jni]
|
启用详细输出
|
-version
|
输出产品版本并退出
|
-showversion
|
输出产品版本并继续
|
-?/-help
|
输出此帮助消息
|
-X
|
输出非标准选项的帮助
|
-esa 或 -enablesystemassertions
|
启用系统断言
|
-dsa 或 -disablesystemassertions
|
禁用系统断言
|
-agentlib:[=<选项>]
|
加载本机代理库 , 例如-agentlib:hprof,另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
|
-agentpath:[=<选项>]
|
按完整路径名加载本机代理库
|
-javaagent:[=<选项>]
|
加载 Java 编程语言代理,请参阅java.lang.instrument
|
-splash:
|
使用指定的图像显示启动屏幕
|
非标准参数
来自于’java -X’的帮助信息。
选项和默认值
|
描述
|
-Xmixed
|
混合模式执行 (默认)
|
-XX:-CITime
|
打印花费在JIT编译上的时间
|
-Xint
|
仅解释模式执行
|
-Xbootclasspath:
|
<用 ; 分隔的目录和 zip/jar 文件>,设置搜索路径以引导类和资源
|
-Xbootclasspath/a:
|
<用 ; 分隔的目录和 zip/jar 文件>,附加在引导类路径末尾
|
-Xbootclasspath/p:
|
<用 ; 分隔的目录和 zip/jar 文件>,置于引导类路径之前
|
-Xdiag
|
显示附加诊断消息
|
-Xnoclassgc
|
禁用类垃圾收集
|
-Xincgc
|
启用增量垃圾收集
|
-Xloggc:
|
将 GC 状态记录在文件中 (带时间戳)
|
-Xbatch
|
禁用后台编译
|
-Xmn
|
设置新生代的初始值和最大值,单位默认是字节,可以使用k,m,g
|
-Xms
|
设置初始 Java 堆大小,单位默认是字节,可以使用k,m,g
|
-Xmx
|
设置最大 Java 堆大小,单位默认是字节,可以使用k,m,g
|
-Xss
|
设置 Java 线程堆栈大小,单位默认是字节,可以使用k,m,g
|
-Xprof
|
输出 cpu 配置文件数据
|
-Xfuture
|
启用最严格的检查, 预期将来的默认值
|
-Xrs
|
减少 Java/VM 对操作系统信号的使用 (请参阅相关文档)
|
-Xcheck:jni
|
对 JNI 函数执行其他检查
|
-Xshare: off
|
不尝试使用共享类数据
|
-Xshare:auto
|
在可能的情况下使用共享类数据 (默认)
|
-Xshare: on
|
要求使用共享类数据, 否则将失败。
|
-XshowSettings
|
显示所有设置并继续
|
-XshowSettings:all
|
显示所有设置并继续
|
-XshowSettings:vm
|
显示所有与 vm 相关的设置并继续
|
-XshowSettings:properties
|
显示所有属性设置并继续
|
-XshowSettings:locale
|
显示所有与区域设置相关的设置并继续
|
jdk1.8中废弃并删除的选项
- ‘-Xincgc’
- ‘-Xrunlibname’
- ‘-XX:CMSIncrementalDutyCycle=percent’
- ‘-XX:CMSIncrementalDutyCycleMin=percent’
- ‘-XX:+CMSIncrementalMode’
- ‘-XX:CMSIncrementalOffset=percent’
- ‘-XX:+CMSIncrementalPacing’
- ‘-XX:CMSIncrementalSafetyFactor=percent’
- ‘-XX:CMSInitiatingPermOccupancyFraction=percent’
- ‘-XX:MaxPermSize=size’
- ‘-XX: PermSize=size’
- ‘-XX:+UseSplitVerifier’
- ‘-XX:+UseStringCache’
四、GC性能方面的考虑
不管是minor GC、major GC和full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM、GC的参数,可以极大的减少由于GC工作而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率。但是调整GC是以个极为复杂的过程,由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要cup个数,内存不同),所以使用的GC种类也会不同。
对于GC的性能主要有2个方面的指标:吞吐量throughput(工作时间不算gc的时间占总的时间比)和暂停pause(gc发生时app对外显示的无法响应)。
五、JVM参数配置的经验&&规则
- 年轻代和老年代的大小
可能很多人都有一种印象,young gen应该比old gen小。笼统说确实如此,因为在最坏情况下young gen里可能所有对象都还活着,而如果它们全部都要晋升到old gen的话,那old gen里的剩余空间必须能容纳下这些对象才行,这就需要old gen比young gen大(否则young GC就无法进行,而必须做full GC才能应付了)。
实际上却不总是这样的。所谓“最坏情况”在很多系统里是永远不会出现的。调优就是要针对实际应用里对象的存活模式来破除这些“最坏情况”的假设带来的限制。
许多Web应用里对象会有这样的特征:
·(a) 有一部分对象几乎一直活着。这些可能是常用数据的cache之类的
·(b) 有一部分对象创建出来没多久之后就没用了。这些很可能会响应一个请求时创建出来的临时对象
·(c) 最后可能还有一些中间的对象,创建出来之后不会马上就死,但也不会一直活着。
如果是这样的模式,那young gen可以设置得非常大,大到每次young GC的时候里面的多数(b)类对象最好已经死了。
想像一下,如果young gen太小,每次满了就触发一次young GC,那么young GC就会很频繁,或许很多临时对象(b)正好还在被是使用(还没死),这样的话young GC的收集效率就会比较低。要避免这样的情况,最好是就是把young gen设大一些。
那old gen怎么办?如果是上面说的情况,那old gen至少要足以装下所有长期存活的对象(a);同时也要留出一定的余地用来容纳young GC没能清理掉的临时对象。 这样,最后调整出来的结果很可能young GC反而比old gen大许多。这完全没问题。
- 较小堆引起的碎片问题
因为年老代的并发收集器使用标记,清除算法,所以不会对堆进行压缩.当堆空间较小时,运行一段时间以后,就会出现”碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记,清除方式进行回收.
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩.
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
- 用64位操作系统,Linux下64位的jdk比32位jdk要慢一些,但是吃得内存更多,吞吐量更大
- XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力
- 使用CMS的好处是老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存, 大约20-80ms的应用程序停顿时间
- 系统停顿的时候可能是GC的问题也可能是程序的问题,多用jmap和jstack查看,然后查看java控制台日志,能看出很多问题。(相关工具的使用方法将在后面介绍)
- 仔细了解自己的应用,如果用了缓存,那么年老代应该大一些,缓存的HashMap不应该无限制长,最大长度也要根据实际情况设定。
- 采用并发回收时,年轻代小一点,年老代要大,因为老年代大用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿
- JVM参数的设置(特别是 –Xmx –Xms –Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold等参数的设置没有一个固定的公式,需要根据PV,old区实际数据 YGC次数等多方面来衡量。xmn设置偏小,也意味着YGC的次数会增多,处理并发访问的能力下降等问题。每个参数的调整都需要经过详细的性能测试,才能找到特定应用的最佳配置。
六、生产环境JVM参数实战
jdk 1.7 生产虚拟机参数(添加到 catalina.sh中)
JAVA_OPTS=-Xmx8000M -Xms8000M -Xmn1024M -XX:PermSize=2048M -XX:MaxPermSize=2048M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:/tmp/gc.log
jdk 1.8 (注意新版本metaspace 代替了旧版本PermGen space)
JAVA_OPTS=-server -Xmx8g -Xms8g -Xmn2g -XX:MetaspaceSize=2g -XX:MaxMetaspaceSize=2g -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -Duser.timezone=GMT+8 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/b2b_interface.dump -Xloggc:/tmp/b2b_interface_gc.log -verbose:gc -Xmixed -XX:-CITime
set JAVA_OPTS=%JAVA_OPTS% -server -Xmx1000m -Xms1000m -Xmn250m -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -Duser.timezone=GMT+8 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/b2b_interface.dump -Xloggc:/b2b_interface_gc.log -verbose:gc -Xmixed -XX:-CITime
版权声明:本文为danyuzhu11原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。