Java常见的垃圾收集器有哪些?

在专栏中总结一下GC调优的相关思路和解决措施,本篇专栏将对GC有一个入门的概念介绍,下一篇专栏将更一步的去写GC的调优和核心思路。

垃圾收集机制是Java的招牌能力,极大地提高了开发效率,并且目前也在不断的发展,这也是面试的热点。

问题是:Java常见的垃圾收集器有哪些?

概述

实际上,GC是和具体JVM实现紧密相关的,不同厂商(IBM、Oracle),不同版本的JVM,提供的选择也不同。接下来主要谈谈最主流的Oracle Jdk的垃圾收集机制。

  • Serial GC

它是最古老的垃圾收集器,其收集工作是单线程的,并且在进行垃圾收集过程中,会进入臭名昭著的"Stop-The-World"状态。

当然,其单线程设计也意味着精简的GC实现,无需维护复杂的数据结构,初始化也简单,所以一直是Client模式下的JVM的默认选项。

其主要采用的算法是标记-整理(Mark-Compact)算法,区别于新生代的复制算法。

Serial GC对应的JVM参数是:

		-XX:+UseSerialGC
  • ParNew GC

明显是新生代GC实现,实际是Serial GC的多线程版本,其对应参数是:

		-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
  • CMS( Concurrent Mark Sweep)GC

基于标记-清除(Mark-Sweep)算法,设计目标是尽量减少停顿的时间,这一点对于Web等反应时间敏感的应用非常重要,一直到今天,仍然有很多系统在使用CMS GC。但是存在着内存碎片化的问题,所以难以避免在长时间运行等情况下发生full GC,导致恶劣的停顿。另外,既然强调了并发(Concurrent),CMS会占用更多的CPU资源,并和用户线程争抢。

-Parrallel GC

在JDK 8中,它是server模式JVM的默认GC选择。算法和Serial GC相似,特点是并行运行,在常见的服务器环境中效果更加高效。
开启选项是:

		-XX:+UseParallelGC

另外Parrallel GC引入了开发者友好的配置型,可以直接设置时间或吞吐量等目标,JVM会自动进行适应性调整,例如:

		-XX:MaxGCPauseMillis=value
		-XX:GCTimeRatio=N // GC时间和用户时间比例 = 1 / (N+1)
  • G1 GC

这是一种兼顾吞吐量和停顿时间的GC实现,是JDK 9以后的默认GC。可以直观的设定停顿时间,将最差情况得到一定的提高。

G1吞吐量和停顿表现都非常不错,并且仍然在不断地改善,与此同时CMS已经在JDK 9中被标记为废弃( deprecated),所以G1 GC值得你深入掌握。

下面会侧重介绍比较通用、基础性的部分:、

  1. 垃圾收集算法有哪些?如何判断一个对象是否可以回收?
  2. 垃圾收集器工作的基本流程。

另外,Java在最新的JDK实现中,还有多种新的GC,后面都会做介绍。

知识扩展

  1. 垃圾收集的原理和基础概念

※第一,自动垃圾收集的前提是清除什么是垃圾,然后才能被释放掉。主要就是两个方面,最主要部分就是对象实例,都是存储在堆上的;还有就是方法区中的元数据等信息,如果该类型不再使用,就会被释放掉内存。

提到了对象实例收集,主要有两种基本算法:引用计数和可达性分析

  • 引用计数

顾名思义,为对象添加一个引用计数,当计数为0表示兑现可回收。这是很多语言的资源回收选择,例如Python,它同时支持Java没有选择的引用计数和垃圾收集机制。

  • Java选择的可达性分析

Java的各种引用关系,各种引用关系在某种程度上将可达性问题还进一步复杂化,这种类型的垃圾收集通常叫做追踪性垃圾收集。原理简单来说,JVM会把虚拟机栈,本地方法栈中正在引用的对象或者常量称为GC Roots,与其之间存在调用关系的就是有用的,不存在调用关系的,就是没用的,没用的就回收。

※第二,常见的垃圾收集算法,主要分为三类:

  • 复制算法

前面讲到的新生代GC,基本都是基于复制算法,原理是将活着的对象复制并且顺序存储,就可以避免内存碎片化。

这样做的缺点:浪费内存空间;另外,对于G1这种分拆成为大量region的GC,复制而不是移动,意味着GC需要维护region之间对象引用关系,这个开销也不小,不管是内存占用或者时间开销。

  • 标记-清除(Mark-Sweep)算法

首先标记没有用的对象然后进行清除

缺点:效率低,出现碎片化问题,导致出现Full GC,暂停时间根根无法接受。

  • 标记-整理(Mark-Compact)

在Mark-Sleep的基础上,为了避免内存碎片化,将清除掉的garbage后的对象按照顺序移动,使他们能占用连续的内存空间。

注意:这些都是GC的基础,实际的GC算法,多用到复合并用算法。

在GC过程中,对应到Eden、Survivor、Tenured等区域会发生什么变化?

实际上取决于具体的GC方式,来熟悉一下垃圾收集流程:

  1. Java应用不断创建对象,分配在Eden区域,当空间占用到一定阈值时,触发minor GC。仍然被引用的对象被复制到JVM选择的Survivor区域,而没有被引用的对象则被回收。图中给存货对象标记了1,这是为了表明对象的存活时间。
    在这里插入图片描述
  2. 经过了一次的复制-回收之后,Eden就会空闲下来,当第二次Eden满了的时候,继续触发Minor GC,这时候另外一个Survivor区域会变成to区域,Eden区域存活对象和From区域对象会被复制到to区域,并且存活年龄计数会被加1。
    在这里插入图片描述
  3. 类似第二步过程会发生很多次,超过阈值的对象会被晋升到老年代,阈值可以自定义:
-XX:MaxTenuringThreshold=<N>

在这里插入图片描述
后面就是老年代GC,具体取决于选择的GC选项,对应不同的算法,下面是一个简单标记-整理算法的过程示意图,老年代中无用对象被清除后,GC会将对象进行整理,以防止内存碎片化。
在这里插入图片描述
通常把老年代GC叫做Major GC,将对整个堆进行的整理叫做Full GC,但是这个也没有那么绝对,因为不同的老年代GC算法其实表现差异很大。例如CMS,并行GC计算,就和以上的不相同。

下面的专栏将会对GC调优进一步解析。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值