前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ZGC回收器到底有多变态?

ZGC回收器到底有多变态?

作者头像
ImportSource
发布2018-08-14 17:22:11
2.6K0
发布2018-08-14 17:22:11
举报
文章被收录于专栏:ImportSourceImportSource

zgc是个什么东东?简单说是个垃圾回收器。

一个低延迟的垃圾回收器!

多少年来,JVM中的各种垃圾回收器都在努力追求着两个目标,暂停时间足够短,同时吞吐量也要不错。为了追求二者兼具,各种垃圾回收器可谓绞尽脑汁,但还是无法同时让两个都足够好,要么暂停时间缩短了但吞吐量下降了,要么吞吐量上去了暂停时间却变长了,真的是操蛋,即使是现在最新的生产可用的G1也是,虽然他也号称是low latency,也可以指定暂停时间,但还是需要你去平衡暂停时间和吞吐量,G1可以说是非常努力了,但还是没有做到极致和傻白甜。

但事情总是发展的,前几天,jdk11的开发团队悄悄的在自己的功能列表中添加了一个叫ZGC的gc。没错,就是我们今天要侃的主角,一个集暂停与吞吐于一身的回收器,听着就是不是被吓尿了,是不是感觉以后都不用对JVM调优了,是不是以后代码可以xjb写了。

来看看它的目标:

看看这些目标!

TB级的堆随便搞!暂停时间10毫秒内!吞吐量最大下降15%!大声告诉我,吓尿没?!

好,继续。

暂停时间不会随着堆的增大而变长!不会!

总体印象

好,接下来,我们还是先对ZGC有个总体上的印象。

1、全新的垃圾回收器。“全新”指的是一点点从草稿然后搞出来,不是基于哪个来优化出来的。

2、使用了Load Barriors技术,而不是使用store Barriors。这是两种不同的技术。store barriors是hotspot里现存的好多垃圾回收器所用的技术。zgc中使用load barrior技术来跟踪堆的状态和对象的状态。

3、单代。它是一个只有一个generation的回收器。

4、Partial Compaction。也是基于部分压缩,这个和G1是一样的。

5、Region-Based GC。它有点像G1,都是基于region,但和G1不一样的是,zgc有更加灵活的region的size schema。这样我们就可以轻松的处理大对象的分配问题了。

6、Immediate Memory Reuse。zgc和G1一样,region们会被及时的清理和压缩和转移,可以让内存的复用更加的及时。

7、NUMA-aware。这是一种内存页合并的硬件技术。

8、Colored Object Pointers。

9、Concurrent。zgc一个非常重要的能力。就是并行和并发干几乎所有的事情。

比如:

  • 1、Marking。
  • 2、Relocation和Compaction。
  • 3、Relocation Set Selection。
  • 4、Reference Processing。
  • 5、JNI WeakRefs Cleaning。
  • 6、StringTable和SymbolTable Cleaning。
  • 7、Class Unloading。

以上这些统统并发(conccurent)搞!zgc团队为他们的这一项能力非常骄傲,这在open jdk的其他垃圾回收器是非常少有的。

目前的状态

1、ZGC目前仅支持Linux/x86_64。

2、性能方面目前是非常牛x的。无论是暂停时间还是吞吐量。

看看一些数字

这是评测结构跑的分数。重点看看蓝色的指标,可以看出ZGC要比Parallel和G1要更好。

再来看看暂停时间的分数:

是不是很夸张。暂停时间远低于他们最初定的目标10ms

GC阶段

这里先放个图,先有个印象,后面会有一个gc过程示例来详细说明。

Heap Regions

堆区域。也被称为:ZPages。

这和G1的region有点像,但和G1不一样的是,region的大小更加灵活和动态。zgc的region不会像G1那样在一开始就被划分为固定大小的region。

zgc的region核心亮点就是:动态。

动态表现为:

  • 1、动态地创建和销毁。
  • 2、动态地决定region的大小。它的最小单位是2MB的一个块。然后每个region的大小就是是2MB*N就是。

而且他有个概念叫:size groups。有三种:

Small:就是一个2MB的region。

Medium:32mb。2MB*16。

Large:N*2MB。

整个heap长这样:

Colored Pointers

是zgc的一个核心概念。你还可以叫它tag pointers,version pointers。

metadata被保存在64-bit的pointer中。目前不支持32位的平台。也不支持CompressedOops。

Virtual Address-masking可以是硬件或操作系统或软件。

先来看看在x86_64上的colored pointer的布局:

一个pointer共64bit。开始的18bit暂时没有被用到(以后有可能要用),然后是四个bit,分别表示Finalizable、Remapped、Marked1、Marked0,这是gc过程中每个对象的状态。最后42bit是用来存储对象的地址。

当是remapped时候,表示不要指向到relocation set(具体relocation set是个什么会在后面的gc示例中说到)中。

当颜色为Finalizable的时候,就只能通过Finalizer来访问到,其他的途径已无法访问。

Linux/x86_64上是Heap Multi-Mapping

下面是在x86_64上的heap中的address space中的pointer们的逻辑映射。

在Solaris/SPARC的heap映射:

Solaris/SPARC上是single heap mapping

Load Barrier

Load Barrier主要用于在对象从heap load的时候。而且只在这一个地方用到load barrier。一旦你过了load barrier并成功的拿到了对象,之后你就可以任意的使用它了,比如访问字段,调用方法等。为什么要加入load barrier呢?它的主要目的就是检查pointer是不是“bad color”(前面我们讲到colored pointers)。如果是一个bad color的pointer,那么就需要走一个慢的路径(slow path),然后采取一些措施然后让他变成good color,然后下次你在load的时候,就会走快的路径(fast path),而不需要做额外的措施了。

bad color:mark 、relocate、remap。

good color:repair、heal。

大部分的情况下的对象引用都是good color。

来看看一个例子:

具体的load barrier实现:

如果不是good color并且对象不为null,那么执行slow_path:

GC过程示例

接下来展示一下zgc中的gc过程。

开始示例之前,先说明下,本图的基本元素。含有箭头的线条我们称之为:pointer。然后每个数字表示object。每个方块表示一个region。

首先从roots开始一直往下连通,如果能够直接连通的,我们认为就是可达的,然后标记为红色。

Pause Mark Start

然后标记1为红色,表示ok。

然后标记2为红色。

然后标记4为红色。

Concurrent Mark

现在标记结束了。接下来进入的阶段是“重新分配准备阶段”:Concurrent Prepare for Relocate。

Relocation就是一个转移的过程。

标记过后,我们发现3,6,7是不同的颜色。

Concurrent Prepare for Relocate

标记过后,就需要确定哪些region中的对象被转移。可以发现含有3、6、7的两个region被列为了Relocation Set,意味着这两个region中的对象将会被relocation。

那么4、5、8要被转移到哪里呢?

接下来进入Pause Relocate Start阶段。

Pause Relocate Start

绿色表示Remapped+Relocate的过程。

当来到4的是,发现它属于Relocation Set的对象,于是把4转移到了最右边的那个全新的region中。然后在下面的Forwarding Table中做个记录。

然后进入到Concurrent Relocate阶段。把4转移了?那5和8怎么办呢?

Concurrent Relocate

这个阶段,负责5和8转移到4现在所在的那个region。

现在5已经被转移到了新region。原来3、4、5所在region已经被清理空了,可以重新被使用了。如下:

同样的做法,把8也转移到新的region里。

同样的又一个region被腾空了,可以被重新使用了。

GC Cycle Completed

好,是不是发现2和5已经无法连通了。接下来进入第二阶段的Pause Mark Start。

Pause Mark Start (Second Cycle)

Concurrent Mark (Second Cycle)

Pause Mark End (Second Cycle)

Concurrent Prepare for Relocate (Second Cycle)

可以发现Forwarding Table已被清空。

Stripe Mark

好,你也许好奇,那么多的region,zgc是怎么进行一个个进行回收的呢?上面只是展示了几个对象而已,几个region而已。

这里就要说到zgc的一个宏观的条纹标记技术:Striped Mark。光听到这名词,你也许不知道具体是怎么做的。

这就是条纹,每个条纹的颜色不同。

条纹标记法会把heap逻辑上分成若干个条纹组。然后把每个gc线程都隔离到它自己的stripe上进行gc。

现在假设有四个GC线程。然后Heap如上所示。

然后把heap分为不同颜色的条纹。

然后再抽象一层stripe分组。

不同颜色的条纹由不同的线程来处理。

但有种情况是有的GC线程提前完成了自己所在stripe的清理工作。此时它会加入到其他的stripe上继续帮助其他的gc线程继续清理其他的stripe(这个思路有点类似工作窃取算法)。

好,以上就是全部。ZGC,一个集暂停与吞吐于一身的GC,一个暂停时间控制在10毫秒以内的GC

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-07-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ImportSource 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档