深入浅出 JVM GC(4)常用 GC 参数介绍

# 前言

从前面的3篇文章中,我们分析了5个垃圾收集器,还有一些 GC 的算法,那么,在 GC 调优中,我们肯定会先判断哪里出现的问题,然后再根据出现的问题进行调优,而调优的手段就是 JVM 提供给我们的那些参数或者说选项,这些参数将会改变 GC 的运行方式。因此,他们显得极为重要。

我们将每一个垃圾收集器相关的参数一个一个娓娓道来,注意,楼主推荐一个小程序:前阿里 JVM 大神寒泉子的公众号里面有个小程序------JVM Pocket,这个小程序介绍了所有的 JVM 参数的作用,你可以在里面搜索你想知道的参数,也可以把你了解的参数写上去供大家参考。公众号:lovestblog。

值得注意的一点是,这些参数可能会重复,还记得我们之前的那张图吗,楼主觉得有必要再发一次:

可以看到,这些收集器会有一些重复,而且,某些参数也是会作用于所有的处理器,因此,我们下面的介绍可能会有一些重复。

还有一点就是,JVM 为我们设置了很多默认的参数,但是,如果可以的话,还是建议使用显式的声明,这样更能表达意图。否则,别人不一定知道我们是否知道这些默认值。

我们开始我们的参数之旅吧!

# 1. Serial 收集器参数

串行收集器,client 的默认收集器,分为年轻代 Serial 和老年代 Serial Old 收集器。

  1. -XX:+UseSerialGC 这个参数就是可以指定使用新生代串行收集器和老年代串行收集器, “+” 号的意思是ture,开启,反之,如果是 “-”号,则是关闭。

  2. -XX:+UseParNewGC 新生代使用 ParNew 回收器,老年代使用串行收集器。

  3. -XX:+UseParallelGC 新生代私用 ParallelGC 回收器,老年代使用串行收集器。

而 Serial 收集器出现的日志为 DefNew .

# 2. ParNew 收集器参数

并行收集器是 Serial 的多线程版本,在 CPU 并行能力强大的计算机上有很大优势。

其中:

  1. -XX:+UseParNewGC 上面说过了,新生代使用 ParNew 收集器,老年代使用串行收集器。

  2. -XX:+UseConcMarkSweepGC: 新生代使用 ParNew 回收器,老年代使用 CMS。

  3. -XX:ParallelGCThreads={value} 这个参数是指定并行 GC 线程的数量,一般最好和 CPU 核心数量相当。默认情况下,当 CPU 数量小于8, ParallelGCThreads 的值等于 CPU 数量,当 CPU 数量大于 8 时,则使用公式:3+((5*CPU)/ 8);同时这个参数只要是并行 GC 都可以使用,不只是 ParNew。

而 ParNew 的 GC 日志则表吸纳出 ParNew。

# 3. PS 收集器参数

全称 Parallel Scavenge 收集器,该收集器是 Java 8 的默认收集器,因为它能够根据系统当前状态给出吞吐量最高的GC 配置。所以,在一些手工调优复杂的场合或者对实时性要求不高的场合,可以使用该处理器。

有哪些参数呢?

  1. -XX:MaxGCPauseMillis 设置最大垃圾收集停顿时间,他的值是一个大于0的整数。ParallelGC 工作时,会调整 Java 堆大小或者其他的一些参数,尽可能的把停顿时间控制在 MaxGCPauseMillis 以内。如果为了将停顿时间设置的很小,将此值也设置的很小,那么 PS 将会把堆设置的也很小,这将会到值频繁 GC ,虽然系统停顿时间小了,但总吞吐量下降了。

  2. -XX:GCTimeRatio 设置吞吐量大小,他的值是一个0 到100之间的整数,假设 GCTimeRatio 的值是 n ,那么系统将花费不超过 1/(1+n) 的时间用于垃圾收集,默认 n 是99,即不超过1% 的时间用于垃圾收集。

  3. -XX:+UseParallelGC 新生代使用 ParallelGC 回收器,老年代使用串行回收器。

  4. -XX:+UseParallelOldGC 新生代使用 ParallelGC 回收器,老年代使用 ParallelOldGC 回收器。

  5. -XX:UseAdaptiveSizePolicy: 打开自适应策略。在这种模式下,新生代的大小,eden 和 Survivor 的比例,晋升老年代的对象年龄等参数会被自动调整。以达到堆大小,吞吐量,停顿时间的平衡点。

聪明的同学相比看出来了,1 和 2 两个参数是矛盾的。因为吞吐量和停顿时间就是矛盾的。所以,要根据应用的特性来进行设置,以达到最优水平。

同时,Parallel Old 收集器也是一种关注吞吐量的并行的老年代回收器。

  1. -XX:+UseParallelOldGC 新生代使用 ParallelGC 回收器,老年代使用 ParallelOldGC 回收器。该参数可以启用 ParallelOldGC。

  2. -XX:ParallelGCGThreads 同时可以指定该参数设置并行线程数量。

而 PS 处理器的 GC 日志则是 PSYoungGen。

# 4. CMS 收集器参数

CMS 处理器关注的是停顿时间。全称 Concurrent Mark Sweep。因为该处理器较为复杂,因此可以使用较多参数。

  1. -XX:-CMSPrecleaningEnabled 不进行预清理,度过我们之前的文章的都知道,CMS 在并发标记和重新标记的这段时间内,会有一个预清理的工作,而这个通过会尝试5秒之内等待来一次 YGC。以免在后面的重新标记阶段耗费大量时间来标记新生代的对象。

  2. -XX:+UseConcMarkSweepGC 此参数将启动 CMS 回收器。默认新生代是 ParNew,也可以设置 Serial 为新生代收集器。该参数等价于 -Xconcgc。

  3. -XX:ParallelGCThreads 由于是并行处理器,当然也可以指定线程数。默认并发线程数是:(ParallelGCThreads + 3)/ 4)。

  4. -XX:ConcGCThreads 或者 -XX:ParallelCMSThreads ;除了上面设置线程的方式,你也可以通过这个两个参数任意一个手工设定 CMS 并发线程数。

  5. -XX:CMSInitiatingOccupancyFraction 由于 CMS 回收器不是独占式的,在垃圾回收的时候应用程序仍在工作,所以需要留出足够的内存给应用程序,否则会触发 FGC。而什么时候运行 CMS GC 呢?通过该参数即可设置,该参数表示的是老年代的内存使用百分比。当达到这个阈值就会执行 CMS。默认是68。 如果老年代内存增长很快,建议降低阈值,避免 FGC,如果增长慢,则可以加大阈值,减少 CMS GC 次数。提高吞吐量。

  6. -XX:+UseCMSCompactAtFullCollection 由于 CMS 使用标记清理算法,内存碎片无法避免。该参数指定每次 CMS 后进行一次碎片整理。

  7. -XX:CMSFullGCsBeforeCompaction 由于每次进行碎片整理将会影响性能,你可以使用该参数设定多少次 CMS 后才进行一次碎片整理,也就是内存压缩。

  8. -XX:+CMSClassUnloadingEnabled 允许对类元数据进行回收。

  9. -XX:CMSInitiatingPermOccupancyFraction 当永久区占用率达到这一百分比时,启动 CMS 回收(前提是 -XX:+CMSClassUnloadingEnabled 激活了)。

  10. -XX:UseCMSInitiatingOccupancyOnly 表示只在到达阈值的时候才进行 CMS 回收。

  11. XX:CMSWaitDuration=2000 由于CMS GC 条件比较简单,JVM有一个线程定时扫描Old区,时间间隔可以通过该参数指定(毫秒单位),默认是2s。

CMS 的 GC 日志 就是 CMS。

# 5. G1 收集器参数

作为 Java 9 的默认垃圾收集器,该收集器和之前的收集器大不相同,该收集器可以工作在young 区,也可以工作在 old 区。有哪些参数呢?

  1. -XX:+UseG1GC 开启 G1 收集器。

  2. -XX:MaxGCPauseMillis 用于指定最大停顿时间,如果任何一次停顿超过这个设置值时,G1 就会尝试调整新生代和老年代的比例,调整堆大小,调整晋升年龄的手段,试图达到目标。和 PS 一样,停顿时间小了,对应的吞吐量也会变小。这点值得注意。

  3. -XX:ParallelGCThreads 由于是并行并发的,可以指定GC 工作线程数量。

  4. -XX:InitiatingHeapOccupancyPercent 该参数可以指定当整个堆使用率达到多少时,触发并发标记周期的执行。默认值时45,即当堆的使用率达到45%,执行并发标记周期,该值一旦设置,始终都不会被 G1修改。也就是说,G1 就算为了满足 MaxGCPauseMillis 也不会修改此值。如果该值设置的很大,导致并发周期迟迟得不到启动,那么引起 FGC 的几率将会变大。如果过小,则会频繁标记,GC 线程抢占应用程序CPU 资源,性能将会下降。

  5. -XX:GCPauseIntervalMillis 设置停顿时间间隔。

# 6. 一些通用参数

在 GC 调优中,还有一些通用的参数。通常是我们的好帮手。

  1. -XX:-+DisableExplicitGC 禁用 System.gc(),由于该方法默认会触发 FGC,并且忽略参数中的 UseG1GC 和 UseConcMarkSweepGC,因此必要时可以禁用该方法。

  2. -XX:+ExplicitGCInvokesConcurrent 该参数可以改变上面的行为,也就是说,System.gc() 后不使用 FGC ,而是使用配置的并发收集器进行并发收集。注意:使用此选项就不要 使用 上面的选项。

  3. -XX:-ScavengeBeforeFullGC 由于大部分 FGC 之前都会 YGC,减轻了 FGC 的压力,缩短了 FGC 的停顿时间,但也可能你不需要这个特性,那么你可以使用这个参数关闭,默认是 ture 开启。

  4. -XX:MaxTenuringThreshold={value} 新生代 to 区的对象在经过多次 GC 后,如果还没有死亡,则认为他是一个老对象,则可以晋升到老年代,而这个年龄(GC 次数)是可以设置的,有就是这个参数。默认值时15。超过15 则认为是无限大(因为age变量时4个 bit,超过15无法表达)。但该参数不是唯一决定对象晋升的条件。当 to 区不够或者改对象年龄已经达到了平均晋升值或者大对象等等条件。

  5. -XX:TargetSurvivorRatio={value} 决定对何时晋升的不仅只有 XX:MaxTenuringThreshold 参数,如果在 Survivor 空间中相同年龄所有对象大小的总和大鱼 Survivor 空间的一半(默认50%),年龄大于或等于该年龄的对象就可以直接进入老年代。无需在乎 XX:MaxTenuringThreshold参数。因此,MaxTenuringThreshold 只是对象晋升的最大年龄。如果将 TargetSurvivorRatio 设置的很小,对象将晋升的很快。

  6. -XX:PretenureSizeThresholds={value} 除了年龄外,对象的体积也是影响晋升的一个关键,也就是大对象。如果一个对象新生代放不下,只能直接通过分配担保机制进入老年代。该参数是设置对象直接晋升到老年代的阈值,单位是字节。只要对象的大小大于此阈值,就会直接绕过新生代,直接进入老年代。注意:这个参数只对 Serial 和 ParNew 有效,ParallelGC 无效,默认情况下该值为0,也就是不指定最大的晋升大小,一切有运行情况决定。

  7. -XX:-UseTLAB 禁用线程本地分配缓存。TLAB 的全称是 Thread LocalAllocation Buffer ,即线程本地线程分配缓存,是一个线程私有的内存区域。该设计是为了加速对象分配速度。由于对象一般都是分配在堆上,而对是线程共享的。因此肯定有锁,虽然使用 CAS 的操作,但性能仍有优化空间。通过为每一个线程分配一个 TLAB 的空间(在 eden 区),可以消除多个线程同步的开销。默认开启。

  8. -XX:TLABSize 指定 TLAB 的大小。

  9. -XX:+PrintTLAB 跟踪 TLAB 的使用情况。用以确定是用多大的 TLABSize。

  10. -XX:+ResizeTLAB 自动调整 TLAB 大小。

同时,对象也可能会在栈上分配,栈上分配,TLAB 分配,堆分配,他们的流程如下:

对象分配流程

还有一些开启 GC 日志的参数,是 GC 调优不可或缺的工具。

  1. -XX:+PrintGCDateStamps 打印 GC 日志时间戳。

  2. -XX:+PrintGCDetails 打印 GC 详情。

  3. -XX:+PrintGCTimeStamps: 打印此次垃圾回收距离jvm开始运行的所耗时间。

  4. -Xloggc:<filename> 将垃圾回收信息输出到指定文件

  5. -verbose:gc 打印 GC 日志

  6. -XX:+PrintGCApplicationStopedTime 查看 gc 造成的应用暂停时间

  7. XX:+PrintTenuringDistribution, 对象晋升的日志

  8. -XX:+HeapDumpOnOutOfMemoryError 内存溢出时输出 dump 文件。

# 总结

好了,我们已经将一些常用的 GC 参数介绍了,当然会有遗漏的,如有遗漏或者介绍有误的,请告知本人。这些参数不仅仅是为了服务大家,同时也是自己做的一个总结,以后就不用到处找了。说白了这就是写博客的好处:总结了自己,也做了备份,同时也可能帮助了别人。

Good Luck!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 原文阅读 前言 这段时间懈怠了,罪过! 最近看到有同事也开始用上了微信公众号写博客了,挺好的~给他们点赞,这博客我...
    码农戏码阅读 5,946评论 2 31
  • 这篇文章是我之前翻阅了不少的书籍以及从网络上收集的一些资料的整理,因此不免有一些不准确的地方,同时不同JDK版本的...
    高广超阅读 15,528评论 3 83
  • # 前言 在 深入浅出 JVM GC(2) 中,我们介绍了一些 GC 算法,GC 名词,同时也留下了一个问题,就...
    莫那一鲁道阅读 1,112评论 1 4
  • Java 虚拟机有自己完善的硬件架构, 如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM 屏蔽了与具体操作系...
    尹小凯阅读 1,678评论 0 10
  • http://www.cnblogs.com/angeldevil/p/3801189.html值得一看 Clas...
    snail_knight阅读 1,409评论 1 0