HotSpot参数分类
标准: - 开头,所有的HotSpot都支持
非标准:-X 开头,特定版本HotSpot支持特定命令
不稳定:-XX 开头,下个版本可能取消
1常见垃圾回收器组合参数设定
-XX:+UseSerialGC Serial New (DefNew) + Serial Old -XX:+UseParNewGC ParNew + SerialOld (这个组合已经很少用 ) -XX:+UseConcMarkSweepGC ParNew + CMS + Serial Old -XX:+UseParallelGC Parallel Scavenge + Parallel Old (1.8默认) -XX:+UseParallelOldGC Parallel Scavenge + Parallel Old -XX:+UseG1GC G1
2、日志打印相关
参数 说明 -XX:+PrintGC 打印GC的简要信息 -XX:+PrintGCDetails 打印GC详细信息 -XX:+PrintGCTimeStamps 打印CG发生的时间戳 -Xloggc:/home/GCEASY/gc-%t.log %t会给文件名添加时间戳后缀,格式是YYYY-MM-DD_HH-MM-SS -XX:+HeapDumpOnOutOfMemoryError 让虚拟机在发生内存溢出时 Dump 出当前的内存堆转储快照,以便分析用 -XX:HeapDumpPath=/tmp/dump.hprof 指定路径
2.1 日志推荐参数:
不推荐下main使用:
很多小伙伴在记录GC日志的时候都喜欢使用UseGCLogFileRotation这个参数,比如:
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/home/GCEASY/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=20M
上面的例子中,JVM的一个日志文件达到了20M以后,就会写入另一个新的文件,最多会有5个日志文件,他们的名字分别是: gc.log.0、gc.log.1、gc.log.2、gc.log.3、gc.log.4.
带来问题 :丢失旧的日志、日志会变混乱、不方便日志集中管理、对日志分析工具不友好
推荐的解决办法:
可以给GC日志的文件后缀加上时间戳,当JVM重启以后,会生成新的日志文件,新的日志也不会覆盖老的日志,只需要在日志文件名中添加%t的后缀即可:
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/home/GCEASY/gc-%t.log
%t会给文件名添加时间戳后缀,格式是YYYY-MM-DD_HH-MM-SS。这样就非常简单了克服了UseGCLogFileRotation存在的所有的问题!
2.1、使用 JVM 参数获取 dump 文件
- 1. -XX:+HeapDumpOnOutOfMemoryError
当OutOfMemoryError发生时自动生成 Heap Dump 文件。
这可是一个非常有用的参数,因为当你需要分析Java内存使用情况时,往往是在OOM(OutOfMemoryError)发生时。
-
2. -XX:+HeapDumpBeforeFullGC
当 JVM 执行 FullGC 前执行 dump。 -
3. -XX:+HeapDumpAfterFullGC
当 JVM 执行 FullGC 后执行 dump。 -
4. -XX:+HeapDumpOnCtrlBreak
交互式获取dump。在控制台按下快捷键Ctrl + Break时,JVM就会转存一下堆快照。 -
5. -XX:HeapDumpPath=d:\test.hprof
指定 dump 文件存储路径。
注意:JVM 生成 Heap Dump 的时候,虚拟机是暂停一切服务的。如果是线上系统执行 Heap Dump 时需要注意。
三 常用参数
配置参数 功能 -Xms 初始堆大小。如:-Xms256m -Xmx 最大堆大小。如:-Xmx512m -Xmn 新生代大小。通常为 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 个 Survivor 空间。实际可用空间为 = Eden + 1 个 Survivor,即 90% -XX:NewSize 设置年轻代大小 -XX:MaxNewSize 设置年轻代最大值 -Xss JDK1.5+ 每个线程堆栈大小为 1M,一般来说如果栈不是很深的话, 1M 是绝对够用了的。 -XX:NewRatio 新生代与老年代的比例,如 –XX:NewRatio=2,则新生代占整个堆空间的1/3,老年代占2/3 -XX:SurvivorRatio 新生代中 Eden 与 Survivor 的比值。默认值为 8。即 Eden 占新生代空间的 8/10,另外两个 Survivor 各占 1/10 -XX:PermSize 永久代(方法区)的初始大小(jdk1.8 废弃) -XX:MaxPermSize 永久代(方法区)的最大值(jdk1.8 废弃) -XX:MetaspaceSize 元空间大小 -XX:MaxTenuringThreshold 设置垃圾最大年龄 -XX:+UseTLAB 使用TLAB,默认打开 -XX:TLABSize 设置TLAB大小 -XX:+PrintFlagsFinal
-XX:+PrintFlagsInitial
查看jvm参数初始值
查看最终值(初始值可能被修改掉)
四、并行收集器参数
4.1. Serial 收集器参数
串行收集器,client 的默认收集器,分为年轻代 Serial 和老年代 Serial Old 收集器。
-
-XX:+UseSerialGC 这个参数就是可以指定使用新生代串行收集器和老年代串行收集器, “+” 号的意思是ture,开启,反之,如果是 “-”号,则是关闭。
-
-XX:+UseParNewGC 新生代使用 ParNew 回收器,老年代使用串行收集器。
-
-XX:+UseParallelGC 新生代私用 ParallelGC 回收器,老年代使用串行收集器。
而 Serial 收集器出现的日志为 DefNew .
4. 2. ParNew 收集器参数
并行收集器是 Serial 的多线程版本,在 CPU 并行能力强大的计算机上有很大优势。
其中:
-
-XX:+UseParNewGC 上面说过了,新生代使用 ParNew 收集器,老年代使用串行收集器。
-
-XX:+UseConcMarkSweepGC: 新生代使用 ParNew 回收器,老年代使用 CMS。
-
-XX:ParallelGCThreads={value} 这个参数是指定并行 GC 线程的数量,一般最好和 CPU 核心数量相当。默认情况下,当 CPU 数量小于8, ParallelGCThreads 的值等于 CPU 数量,当 CPU 数量大于 8 时,则使用公式:3+((5*CPU)/ 8);同时这个参数只要是并行 GC 都可以使用,不只是 ParNew。
而 ParNew 的 GC 日志则表吸纳出 ParNew。
4.3. PS 收集器参数
全称 Parallel Scavenge 收集器,该收集器是 Java 8 的默认收集器,因为它能够根据系统当前状态给出吞吐量最高的GC 配置。所以,在一些手工调优复杂的场合或者对实时性要求不高的场合,可以使用该处理器。
有哪些参数呢?
-
-XX:MaxGCPauseMillis 设置最大垃圾收集停顿时间,他的值是一个大于0的整数。ParallelGC 工作时,会调整 Java 堆大小或者其他的一些参数,尽可能的把停顿时间控制在 MaxGCPauseMillis 以内。如果为了将停顿时间设置的很小,将此值也设置的很小,那么 PS 将会把堆设置的也很小,这将会到值频繁 GC ,虽然系统停顿时间小了,但总吞吐量下降了。
-
-XX:GCTimeRatio 设置吞吐量大小,他的值是一个0 到100之间的整数,假设 GCTimeRatio 的值是 n ,那么系统将花费不超过 1/(1+n) 的时间用于垃圾收集,默认 n 是99,即不超过1% 的时间用于垃圾收集。
-
-XX:+UseParallelGC 新生代使用 ParallelGC 回收器,老年代使用串行回收器。
-
-XX:+UseParallelOldGC 新生代使用 ParallelGC 回收器,老年代使用 ParallelOldGC 回收器。
-
-XX:UseAdaptiveSizePolicy: 打开自适应策略。在这种模式下,新生代的大小,eden 和 Survivor 的比例,晋升老年代的对象年龄等参数会被自动调整。以达到堆大小,吞吐量,停顿时间的平衡点。
聪明的同学相比看出来了,1 和 2 两个参数是矛盾的。因为吞吐量和停顿时间就是矛盾的。所以,要根据应用的特性来进行设置,以达到最优水平。
同时,Parallel Old 收集器也是一种关注吞吐量的并行的老年代回收器。
-
-XX:+UseParallelOldGC 新生代使用 ParallelGC 回收器,老年代使用 ParallelOldGC 回收器。该参数可以启用 ParallelOldGC。
-
-XX:ParallelGCGThreads 同时可以指定该参数设置并行线程数量。
而 PS 处理器的 GC 日志则是 PSYoungGen。
4.4. CMS 收集器参数
CMS 处理器关注的是停顿时间。全称 Concurrent Mark Sweep。因为该处理器较为复杂,因此可以使用较多参数。
-
-XX:-CMSPrecleaningEnabled 不进行预清理,度过我们之前的文章的都知道,CMS 在并发标记和重新标记的这段时间内,会有一个预清理的工作,而这个通过会尝试5秒之内等待来一次 YGC。以免在后面的重新标记阶段耗费大量时间来标记新生代的对象。
-
-XX:+UseConcMarkSweepGC 此参数将启动 CMS 回收器。默认新生代是 ParNew,也可以设置 Serial 为新生代收集器。该参数等价于 -Xconcgc。
-
-XX:ParallelGCThreads 由于是并行处理器,当然也可以指定线程数。默认并发线程数是:(ParallelGCThreads + 3)/ 4)。
-
-XX:ConcGCThreads 或者 -XX:ParallelCMSThreads ;除了上面设置线程的方式,你也可以通过这个两个参数任意一个手工设定 CMS 并发线程数。
-
-XX:CMSInitiatingOccupancyFraction 由于 CMS 回收器不是独占式的,在垃圾回收的时候应用程序仍在工作,所以需要留出足够的内存给应用程序,否则会触发 FGC。而什么时候运行 CMS GC 呢?通过该参数即可设置,该参数表示的是老年代的内存使用百分比。当达到这个阈值就会执行 CMS。默认是68。 如果老年代内存增长很快,建议降低阈值,避免 FGC,如果增长慢,则可以加大阈值,减少 CMS GC 次数。提高吞吐量。
-
-XX:+UseCMSCompactAtFullCollection 由于 CMS 使用标记清理算法,内存碎片无法避免。该参数指定每次 CMS 后进行一次碎片整理。
-
-XX:CMSFullGCsBeforeCompaction 多少次FGC之后进行压缩 由于每次进行碎片整理将会影响性能,你可以使用该参数设定多少次 CMS 后才进行一次碎片整理,也就是内存压缩。
-
-XX:+CMSClassUnloadingEnabled 允许对类元数据进行回收。
-
-XX:CMSInitiatingPermOccupancyFraction 当永久区占用率达到这一百分比时,启动 CMS 回收(前提是 -XX:+CMSClassUnloadingEnabled 激活了)。
-
-XX:UseCMSInitiatingOccupancyOnly 表示只在到达阈值的时候才进行 CMS 回收。
-
XX:CMSWaitDuration=2000 由于CMS GC 条件比较简单,JVM有一个线程定时扫描Old区,时间间隔可以通过该参数指定(毫秒单位),默认是2s。
CMS 的 GC 日志 就是 CMS。
4.5. G1 收集器参数
作为 Java 9 的默认垃圾收集器,该收集器和之前的收集器大不相同,该收集器可以工作在young 区,也可以工作在 old 区。有哪些参数呢?
-
-XX:+UseG1GC 开启 G1 收集器。
-
-XX:MaxGCPauseMillis 用于指定最大停顿时间,如果任何一次停顿超过这个设置值时,G1 就会尝试调整新生代和老年代的比例,调整堆大小,调整晋升年龄的手段,试图达到目标。和 PS 一样,停顿时间小了,对应的吞吐量也会变小。这点值得注意。
-
-XX:ParallelGCThreads 由于是并行并发的,可以指定GC 工作线程数量。
-
-XX:InitiatingHeapOccupancyPercent 该参数可以指定当整个堆使用率达到多少时,触发并发标记周期的执行。默认值时45,即当堆的使用率达到45%,执行并发标记周期,该值一旦设置,始终都不会被 G1修改。也就是说,G1 就算为了满足 MaxGCPauseMillis 也不会修改此值。如果该值设置的很大,导致并发周期迟迟得不到启动,那么引起 FGC 的几率将会变大。如果过小,则会频繁标记,GC 线程抢占应用程序CPU 资源,性能将会下降。
-
-XX:GCPauseIntervalMillis 设置停顿时间间隔。
-
-XX:+G1HeapRegionSize 分区大小,建议逐渐增大该值,1 2 4 8 16 32。 随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长 ZGC做了改进(动态区块大小)
-
-XX:G1NewSizePercent 新生代最小比例,默认为5%
-
-XX:G1MaxNewSizePercent 新生代最大比例,默认为60%
-
-XX:GCTimeRatio GC时间建议比例,G1会根据这个值调整堆空间
-
-XX:ConcGCThreads 线程数量
6. 一些通用参数
在 GC 调优中,还有一些通用的参数。通常是我们的好帮手。
-
-XX:-+DisableExplicitGC 禁用 System.gc(),由于该方法默认会触发 FGC,并且忽略参数中的 UseG1GC 和 UseConcMarkSweepGC,因此必要时可以禁用该方法。
-
-XX:+ExplicitGCInvokesConcurrent 该参数可以改变上面的行为,也就是说,System.gc() 后不使用 FGC ,而是使用配置的并发收集器进行并发收集。注意:使用此选项就不要 使用 上面的选项。
-
-XX:-ScavengeBeforeFullGC 由于大部分 FGC 之前都会 YGC,减轻了 FGC 的压力,缩短了 FGC 的停顿时间,但也可能你不需要这个特性,那么你可以使用这个参数关闭,默认是 ture 开启。
-
-XX:MaxTenuringThreshold={value} 新生代 to 区的对象在经过多次 GC 后,如果还没有死亡,则认为他是一个老对象,则可以晋升到老年代,而这个年龄(GC 次数)是可以设置的,有就是这个参数。默认值时15。超过15 则认为是无限大(因为age变量时4个 bit,超过15无法表达)。但该参数不是唯一决定对象晋升的条件。当 to 区不够或者改对象年龄已经达到了平均晋升值或者大对象等等条件。
-
-XX:TargetSurvivorRatio={value} 决定对何时晋升的不仅只有 XX:MaxTenuringThreshold 参数,如果在 Survivor 空间中相同年龄所有对象大小的总和大鱼 Survivor 空间的一半(默认50%),年龄大于或等于该年龄的对象就可以直接进入老年代。无需在乎 XX:MaxTenuringThreshold参数。因此,MaxTenuringThreshold 只是对象晋升的最大年龄。如果将 TargetSurvivorRatio 设置的很小,对象将晋升的很快。
-
-XX:PretenureSizeThresholds={value} 除了年龄外,对象的体积也是影响晋升的一个关键,也就是大对象。如果一个对象新生代放不下,只能直接通过分配担保机制进入老年代。该参数是设置对象直接晋升到老年代的阈值,单位是字节。只要对象的大小大于此阈值,就会直接绕过新生代,直接进入老年代。注意:这个参数只对 Serial 和 ParNew 有效,ParallelGC 无效,默认情况下该值为0,也就是不指定最大的晋升大小,一切有运行情况决定。
-
-XX:-UseTLAB 禁用线程本地分配缓存。TLAB 的全称是 Thread LocalAllocation Buffer ,即线程本地线程分配缓存,是一个线程私有的内存区域。该设计是为了加速对象分配速度。由于对象一般都是分配在堆上,而对是线程共享的。因此肯定有锁,虽然使用 CAS 的操作,但性能仍有优化空间。通过为每一个线程分配一个 TLAB 的空间(在 eden 区),可以消除多个线程同步的开销。默认开启。
-
-XX:TLABSize 指定 TLAB 的大小。
-
-XX:+PrintTLAB 跟踪 TLAB 的使用情况。用以确定是用多大的 TLABSize。
-
-XX:+ResizeTLAB 自动调整 TLAB 大小。
同时,对象也可能会在栈上分配,栈上分配,TLAB 分配,堆分配,他们的流程如下: