JVM垃圾收集

目录

  1. 内存区域回顾
  2. 机制介绍
  3. 收集器介绍
  4. 调优

内存区域回顾

垃圾回收机制

Java 对象生命周期

根搜索算法

从GC Roots对象为起点,开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时,此对象即为不可用,被判定为可回收对象。

标记过程

垃圾收集算法

堆内存区域划分

垃圾收集器

Serial - 新生代串行收集器

  • 使用单线程进行垃圾回收
  • 独占式
  • 优点:实现简单,处理高效
  • 缺点:Stop The World
  • 使用-XX:+UseSerialGC指定使用
  • JVM在Client模式下默认垃圾收集器

ParNew - 新生代并行收集器

  • 实现和Serial相同,仅将GC线程改成多线程
  • 优点:在多CPU情况下优于Serial
  • 缺点:Stop The World
  • -XX:+UseParNewGC
  • GC线程数,-XX:ParallelGCThreads,
  • 当CPU个数 < 8,ParallelGCThreads=CPU个数
  • 当CPU个数 > 8,ParallelGCThreads=3 + ( (5 * CPU个数) / 8)

Parallel Scavenge - 新生代并行收集器

线程模型和ParNew相同,区别在于Parallel Scavenge收集器的目标是达到一个可以控制的吞吐量

  • -XX:+UseParallelGC,指定使用
  • -XX:MaxGCPauseMillis,设置最大停顿时间,大于0的整数
  • -XX:GCTimeRatio,设置吞吐量大小,0~100整数,即运行用户代码时间 / 垃圾收集时间,默认值为99
  • -XX:+UseAdaptiveSizePolicy 自适应GC策略开关,在自适应模式下,新生代大小,survivor和eden区的比例、晋升老年代对象年龄等参数会被自动调整,以达到最合适的停顿时间,或最大吞吐量。

Serial Old - 老年代串行收集器

  • 使用标记-整理算法
  • 和Serial一样是串行独占式回收器
  • 可和Serial,ParNew 搭配使用
  • 缺点停顿时间可能会比较长

Parallel Old - 老年代并行收集器

  • 使用标记-整理算法
  • 和Parallel Scavenge一样是并行多线程收集器,也是关注于吞吐量
  • -XX:+UseParallelOldGC
  • 缺点停顿时间可能会比较长

CMS - 老年代并发收集器

全称:Concurrent Mark Sweep

  • 基于标记-清除算法
  • 一种以获取最短停顿时间为目标的收集器

初始标记、重新标记仍然需要“Stop The world”。初始标记只标记GC Roots能直接关联到的对象,速度很快,时间很短。并发标记进行GC Roots Tracing,比较耗时。重新标记修正并发标记期间,程序继续运行导致的标记变动。由于整个过程中耗时最长的并发标记和并发清除阶段,GC线程可以与用户线程一起工作,总体上来说CMS是一款并发收集器,这也是CMS停顿时间较短的原因。

  • -XX:+UseConcMarkSweepGC 新生代使用并行收集器,老年代使用CMS + Serial Old
几个缺点
  • Cpu很敏感,并发阶段默认线程数是(CPU数量+3)/ 4 , CPU不足4个时,对程序性能影响较大
  • 无法处理浮动垃圾,清理阶段,用户线程继续运行会产生新的垃圾,可能出现“Concurrent Mode Failure”失败
  • CMS使用标记-清除算法,会产生大量空间碎片
优化方案
  • -XX:CMSInitiatingOccupancyFraction, 设置CMS收集器老年代使用多少空间会被激活,另外当出现“Concurrent Mode Failure”时,将临时启用Serial Old收集器来重新对老年代进行收集
  • -XX:+UseCMSCompactAtFullCollection, 开关参数,表示每次full GC后执行一次碎片整理。-XX:CMSFullGCsBeforeCompaction, 设置执行多少次full GC后,来一次碎片整理

垃圾收集参数总结

参考:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

两种参数格式:

  • 开关参数,比如 -XX:+UseSerialGC,“+”代表开,“-”代表关
  • 值参数,比如 -XX:ParallelGCThreads=4
串行回收器(Serial + Serial Old)

-XX:+UseSerialGC 在新生代和老年代中使用串行收集器 -XX:SurvivorRatio 设置Eden与Survivor区大小比例 -XX:PretenureSizeThreshold 设置大对象直接进入老年代的阈值

并行GC(ParNew + CMS + Serial Old)
  • -XX:+UseParNewGC 在新生代使用并行收集器,默认老年代使用Serial Old,ParNew + Serial Old 已过期,不再推荐使用
  • -XX:+UseConcMarkSweepGC 新生代使用并行收集器,老年代使用CMS + Serial Old
  • -XX:ParallelGCThreads 设置用于垃圾回收的线程数
  • -XX:CMSInitiatingOccupancyFraction 设置CMS收集器在老年代空间被使用多少后触发, JDK7中默认为92%, CMSInitiatingOccupancyFraction = (100 - MinHeapFreeRatio) + (CMSTriggerRatio * MinHeapFreeRatio / 100)
  • -XX:+UseCMSCompactAtFullCollection 设置CMS收集器在完成垃圾收集后是否进行一次内存碎片整理,默认为true
  • -XX:CMSFullGCsBeforeCompaction 设定多少次CMS垃圾回收后,进行一次内存碎片整理,默认为0
  • -XX:+CMSClassUnloadingEnabled 允许对类元数据进行回收
  • -XX:CMSInitiatingPermOccupancyFraction 当永久代占用率达到这个百分比时,启用CMS回收(前提先开启CMSClassUnloadingEnabled)
并行GC(Parallel Scavenge + Parallel Old)
  • -XX:UseParallelGC 新生代使用Parallel Scavenge,server模式下默认开启
  • -XX:UseParallelOldGC 年老代使用Parallel Old, server模式下默认开启
  • -XX:ParallelGCThreads 设置用于垃圾回收的线程数
  • -XX:MaxGCPauseMillis 设置最大垃圾收集停顿时间
  • -XX:GCTimeRatio 设置吞吐量大小,它的值是一个0~100之间的整数,执行用户代码的时间 / 垃圾收集时间
  • -XX:+UseAdaptiveSizePolicy 打开自适应GC策略
  • -XX:+PrintAdaptiveSizePolicy 打印自适应分代大小调整信息
其他
  • -XX:MaxTenuringThreshold 设置对象进入老年代的年龄最大值,每一次Minor GC后,对象年龄加1,默认值15,使用ConcMarkSweep时默认6
  • -XX:+DisableExplicitGC 禁用显式GC,System.gc() 失效
  • -XX:+PrintGCDetails 显示GC日志详细信息
  • -Xloggc:<filename> 将GC日志输出到日志文件
  • -Xmx 堆最大大小
  • -Xms 堆初始大小
  • -Xmn 新生代大小,相当于NewSize和MaxNewSize固定为相同的值
  • -XX:NewSize 新生代初始大小
  • -XX:MaxNewSize 新生代最大大小
  • -XX:PermSize 永久代初始大小
  • -XX:MaxPermSize 永久代最大大小
  • -XX:+PrintFlagsFinal 打印最终的参数值
  • -XX:+PrintCommandLineFlags

内存分配和回收策略

  • 对象优先在Eden区分配
  • 大对象直接进入老年代, -XX:PretenureSizeThreshold, 设置大对象直接进入老年代的大小阈值。只在Serial GC 和ParNew GC时有效,尽量在程序中避免大对象的存在
  • 长期存活的对象进入老年代, -XX:MaxTenuringThreshold, 对象经历MinorGC的次数,默认为15,不一定非要到达这个年龄才进入老年代。
  • 空间分配担保

调优

GC日志收集参数

  • -verbose:gc
  • -XX:+PrintGCDetails
  • -XX:+PrintGCDateStamps 显示gc日志时间年月日时分秒
  • -XX:+PrintGCTimeStamps 显示gc日志距启动的时长
  • -Xloggc:gcfile
  • -XX:+HeapDumpOnOutOfMemoryError
  • -XX:HeapDumpPath

GC日志解读

Times: user - 用户态消耗的cpu时间 sys - 内核态消耗的cpu时间 real - 操作从开始到结束经过的墙钟时间

GC日志收集分析工具

  • jmap
  • jstat / jstatd
  • jconsole
  • jVisualVM

上面工具的都包含在jdk bin目录下

  • GCViewer

减少Full GC

  • 将新对象预留在新生代
  1. 增大新生代空间
  2. 增大survivor区大小,-XX:SurvivorRatio,默认值8
  3. 提高from区利用率 -XX:TargetSurvivorRatio, 默认值50
  • 防止永久代满导致full GC
  • 谨慎使用System.gc() // 堆外内存相关, -XX:+DisableExplicitGC --禁用

选择合适的垃圾收集器

吞吐量优先

使用ParallelGC + ParallelOldGC

降低停顿时间

使用ParNewGC + CMS,CMS对老年代的回收暂停时间远远小于ParallelOld

案例

见《jvm调优案例-xwiki吞吐量调优》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Duncan's Blog

JAVA虚拟机了解

1.JDK(Java Developmen Kit):将Java程序设计语言,Java虚拟机和Java API类库这三部分统称为JDK.

1502
来自专栏于晓飞的专栏

Android GC Log

最近在研究Android内存垃圾回收的内容,遇到一些自己之前不知道的技巧和方法。现在分享一种简单的在Logcat中可以看到垃圾回收状态的方法。经常关注Logca...

1771
来自专栏牛肉圆粉不加葱

JVM GC 那些事(三)- 垃圾收集器

前两篇文章分别介绍了JVM 运行时内存划分和堆上的内存分配机制,本文将对垃圾收集器进行介绍,先来看下面这幅图:

552
来自专栏JavaEdge

HotSpot垃圾收集器1 Serial垃圾收集器2 ParNew垃圾收集器3 Parallel Scavenge垃圾收集器老年代垃圾收集器1 Serial Old垃圾收集器2 Parallel Ol

4078
来自专栏Zephery

java分代回收

一、新生代内存的回收(minor GC)主要采用复制算法,下图展示了minor GC的执行过程。 ? 二、对于新生代和旧生代,JVM可使用很多种垃圾回收器进行垃...

36011
来自专栏纯洁的微笑

jvm系列(三):GC算法 垃圾收集器

概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了。 ...

2996
来自专栏Java开发者杂谈

JVM GC杂谈之理论入门

GC杂谈之理论入门 ---- JVM堆布局介绍 ​ JVM堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ...

3428
来自专栏java 成神之路

JVM(HotSpot) 垃圾收集器

36914
来自专栏Jimoer

JVM学习记录-垃圾收集器

1623
来自专栏无题

GC优化案例4:虚引用过多导致CMS Remark阶段时间过长

对GC优化的案例进行的系列总结(四): 现象 上图很明显(公司内部监控没有区分Old GC和Full GC)Old GC耗时严重,大致看了几天的监控,基本上每...

7646

扫码关注云+社区

领取腾讯云代金券