JVM专栏-3.垃圾收集器

在垃圾收集器的上下文中并发并行的意义

  • 并行(Parallel): 并行描述的是多条垃圾收集器线程之间的关系,说明同一时间有多条这样的线程在协同工作,通常默认此时用户线程是处于等待状态
  • 并发(Concurrent): 并发描述的是垃圾收集器线程和用户线程之间的关系,说明同一时间垃圾收集器线程和用户线程都在运行。由于用户线程并未被冻结,所以程序仍然能响应服务请求,但由于垃圾收集器线程占用了一部分系统资源,此时应用程序的处理的吞吐量将受到一定的影响

一.新生代收集器

1.Serial收集器

单线程垃圾收集器、最基本、发展最悠久。采用复制算法,它的单线程的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程(Stop The World),直到它收集结束。偶尔用在桌面应用中。

2.ParNew收集器

实质上就是 Serial收集器的多线程并行版本版本,所有的可控参数,收集算法,对象分配规则,回收策略与Serial收集器完全一直

可多线程收集垃圾,收集新生代,使用收集算法

3.Parallel Scavenge收集器

基于标记-复制算法也是能够并行收集的多线程收集器,

特点:

Parallel Scavenge收集器的目标是希望达到一个可控制的吞吐量(Throughput),所谓的吞吐量就是处理器用于运行用户代码的时间与处理器的总消耗时间的比值,多线程收集器,其注重点在于尽可能的缩短垃圾收集时用户线程的停顿时间。
吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 运行垃圾收集时间) 吞吐量=运行用户代码时间 / (运行用户代码时间+运行垃圾收集时间) 吞吐量=运行用户代码时间/(运行用户代码时间+运行垃圾收集时间)
Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量:

- 控制垃圾收集停顿时间(允许的值是一个大于0的毫秒数,收集器将尽力保证内存回收花费的时间不超过用户设定值,但最大停顿时间过短必然会导致新生代的内存大小变小,垃圾回收频率变高,效率可能降低。)
-XX:MaxGCPauseMillis

- 设置吞吐量大小(允许的值为一个正整数,表示用户期望虚拟机消耗在Gc上的时间不超过程序运行时间的1/(1+N),默认是99,含义就是收集器的时间消耗不超过总运行时间的1%)
-XX:GCTimeRatio

由于与吞吐量关系密切,Parallel Scavenge也被称为“吞吐量优先收集器”,该收集器还有一个参数为“-XX:+UseAdaptiveSizePolicy”,这是一个开关参数,激活该参数之后,就不需要人工指定新生代的大小等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态的调整这些参数以提供最合适的停顿时间或者最大的吞吐量。这种调节方式称为垃圾收集的自适应调节策略(GC Ergonomics),我们只需要配置内存基本信息(如设置-Xmx设置最大堆,然后使用-XX:MaxGCPauseMillis 参数或者-XX:GCTimeRation参数)具体细节参数的调节工作就由虚拟机完成了。

二.老年代收集器

4.Serial Old收集器

是Serial收集器的老年代版本,也是单线程收集器,采用标记-整理算法。

5.Parallel Old收集器

Parallel Scavenge收集器的老年代版本,也就是我们常常看到的(PS MarkSweep),支持多线程并行收集,基于标记-整理算法。

6.CMS收集器

Concurrent Mark Sweep,采用标记-清除算法,用于老年代,常与ParNew协同工作。
注:并行是指同一时刻同时做多件事情,而并发是指同一时间间隔内做多件事情

工作过程
  • 初始标记(需要STW)
    标记老年代中所有的GC Roots对象和年轻代中活着的对象引用到的老年代的对象,时间短;
  • 并发标记
    从“初始标记”阶段标记的对象开始找出所有存活的对象;
  • 重新标记(需要STW)
    用来处理前一个阶段因为引用关系改变导致没有标记到的存活对象,时间短;
  • 并发清理
    清除那些没有标记的对象并且回收空间。
优点:

并发收集,低停顿

缺点:

占用大量的cpu资源、无法处理浮点垃圾、出现Concurrent Mode Failure、空间碎片。

为什么会出现并发失败(Concurrent Mode Failure)?

因为在垃圾收集期间,用户线程还在持续运行,所以需要预留足够的内存空间给用户线程使用,如果预留的这部分内存无法满足程序分配新对象的需要,就会出现一次并发失败(Concurrent Mode Failure) ,这个是时候虚拟机将不得不开启后备预案,冻结用户线程,临时启用Serial Old 收集器来重新进行老年代的垃圾收集,所以参数-XXCMSInitiatingOccupancyFraction 的设置比例很重要。

7.G1收集器

G1(Garbage First)垃圾收集器是当今垃圾回收技术最前沿的成果之一,早在JDK7就已加入JVM的收集器大家庭中,JDK9中取代Parallel Scavenge 和Parallel Old组合成为默认垃圾收集器。

分代转分区

之前的垃圾收集器,进行收集的范围要么是整个新生代(Minor GC),要么就是整个老年代(Major GC) ,要么就是整个堆(Full GC),G1面向内存的任何部分组成回收集(Collection Set,一般称为CSet),进行回收,回收标准不再是判断属于那个分代,而是那块内存中存放的垃圾数量最多,回收的利益最大。

G1虽然也是遵循分代收集理论,但是不再以固定的大小和固定数量的分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个region根据需要扮演新生代的Eden区,Survivor空间,或者老年代。

Humongous区

专门用来存储大对象,G1认为只要大小超过一个Region容量一半的对象即可判定为大对象。

工作过程
  • 初始标记(需要STW):

标记GC Root能够直接关联到的对象,该阶段需要短暂停顿,但是耗时很短

  • 并发标记

从GC Root开始对堆中的对象进行可达性分析,递归扫描整个堆里的对象图,找到要回收的对象,该阶段耗时比较长,可以与用户程序并发执行

  • 最终标记(需要STW)

对用户线程做一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录

  • 筛选回收(需要STW)

负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划。然后把决定回收的那一部分的Region的存活对象复制到空的Region中,再清理掉整个旧的Region的全部空间。这里的操作涉及到存活对象的移动,是必须暂停用户线程的,由多条收集器线程并行完成的

优势:
  • 并行(多核CPU)与并发;
  • 分代收集(新生代和老年代区分不明显);
  • 空间整合,G1从整体上来看是基于“标记-整理”算法实现的,从局部两个region之间又是基于”标记-复制“算法实现。这两种算法都意味着G1运作期间不会产生内存碎片;
  • 限制收集范围,可预测的停顿。
缺点:

需要额外占用百分之十到百分之二十内存

搭配组合:

默认垃圾回收方式 代表垃圾回收器

默认垃圾回收方式代表垃圾回收器
UseSerialGC“Serial” + “Serial Old”
UseParNewGC“ParNew” + “Serial Old”
UseConcMarkSweepGC“ParNew” + “CMS”
UseParallelGC“Parallel Scavenge” + “Parallel Old”
UseParallelOldGC“Parallel Scavenge” + “Parallel Old”

JVM日志打印详情

# 必备
-XX:+PrintGCDetails 
# 打印对象分布情况
-XX:+PrintGCDateStamps 
-XX:+PrintTenuringDistribution 
# 每次发生GC后查看下堆前后的内存情况
-XX:+PrintHeapAtGC 
# 打印引用信息
-XX:+PrintReferenceGC 
# STW时间
-XX:+PrintGCApplicationStoppedTime

# 可选
-XX:+PrintSafepointStatistics 
-XX:PrintSafepointStatisticsCount=1

# GC日志输出的文件路径
-Xloggc:/path/to/gc-%t.log
# 开启日志文件分割
-XX:+UseGCLogFileRotation 
# 最多分割几个文件,超过之后从头文件开始写
-XX:NumberOfGCLogFiles=14
# 每个文件上限大小,超过就触发分割
-XX:GCLogFileSize=100M

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值