代表Java未来的ZGC深度剖析牛逼

上传人:ja****ee 文档编号:143102344 上传时间:2020-08-26 格式:DOC 页数:17 大小:1.48MB
返回 下载 相关 举报
代表Java未来的ZGC深度剖析牛逼_第1页
第1页 / 共17页
代表Java未来的ZGC深度剖析牛逼_第2页
第2页 / 共17页
代表Java未来的ZGC深度剖析牛逼_第3页
第3页 / 共17页
代表Java未来的ZGC深度剖析牛逼_第4页
第4页 / 共17页
代表Java未来的ZGC深度剖析牛逼_第5页
第5页 / 共17页
点击查看更多>>
资源描述

《代表Java未来的ZGC深度剖析牛逼》由会员分享,可在线阅读,更多相关《代表Java未来的ZGC深度剖析牛逼(17页珍藏版)》请在金锄头文库上搜索。

1、如下图所示,ZGC的目标主要有4个:o 支持TB量级的堆。这你受得了吗?我们生产环境的硬盘还没有上TB呢,这应该可以满足未来十年内,所有JAVA应用的需求了吧。o 最大GC停顿时间不超10ms。这你受得了吗?目前一般线上环境运行良好的JAVA应用Minor GC停顿时间在10ms左右,Major GC一般都需要100ms以上(G1可以调节停顿时间,但是如果调的过低的话,反而会适得其反),之所以能做到这一点是因为它的停顿时间主要跟Root扫描有关,而Root数量和堆大小是没有任何关系的。o 奠定未来GC特性的基础。牛逼,牛逼!o 最糟糕的情况下吞吐量会降低15%。这都不是事,停顿时间足够优秀。至

2、于吞吐量,通过扩容分分钟解决。另外,Oracle官方提到了它最大的优点是:它的停顿时间不会随着堆的增大而增长!也就是说,几十G堆的停顿时间是10ms以下,几百G甚至上T堆的停顿时间也是10ms以下。ZGC概述接下来从几个维度概述一下ZGC。1. New GC2. Single Generation3. Region Based4. Partial Compaction5. NUMA-aware6. Colored Pointers7. Load Barriers8. ZGC tuning9. Change LogNew GCZGC是一个全新的垃圾回收器,它完全不同以往HotSpot的任何垃圾回

3、收器,比如:PS、CMS、G1等。如果真要说它最像谁的话,那应该是Azul公司的商业化垃圾回收器:C4,ZGC所采用的算法就是Azul Systems很多年前提出的Pauseless GC,而实现上它介于早期Azul VM的Pauseless GC与后来Zing VM的C4之间。不过需要说明的是,JDK11中ZGC只能运行在Linux64操作系统之上。JDK14新增支持了MacOS和Window平台:如下图所示,是ZGC和Parallel以及G1的压测对比结果(CMS在JDK9中已经被标记deprecated,更高版本中已经被彻底移除,所以不在对比范围内)。我们可以明显的看到,停顿时间方面,Z

4、GC是100%不超过10ms的,简直是秒天秒地般的存在:接下来,再看一下ZGC的垃圾回收过程,如下图所示。由图我们可知,ZGC依然没有做到整个GC过程完全并发执行,依然有3个STW阶段,其他3个阶段都是并发执行阶段:o Pause Mark Start这一步就是初始化标记,和CMS以及G1一样,主要做Root集合扫描,GC Root是一组必须活跃的引用,而不是对象。例如:活跃的栈帧里指向GC堆中的对象引用、Bootstrap/System类加载器加载的类、JNI Handles、引用类型的静态变量、String常量池里面的引用、线程栈/本地(native)栈里面的对象指针等,但不包括GC堆里的

5、对象指针。所以这一步骤的STW时间非常短暂,并且和堆大小没有任何关系。不过会根据线程的多少、线程栈的大小之类的而变化。o Concurrent Mark/Remap第二步就是并发标记阶段,这个阶段在第一步的基础上,继续往下标记存活的对象。并发标记后,还会有一个短暂的暂停(Pause Mark End),确保所有对象都被标记。o Concurrent Prepare for Relocate即为Relocation阶段做准备,选取接下来需要标记整理的Region集合,这个阶段也是并发执行的。接下来又会有一个Pause Relocate Start步骤,它的作用是只移动Root集合对象引用,所以这

6、个STW阶段也不会停顿太长时间。relocateo Concurrent Relocate最后,就是并发回收阶段了,这个阶段会把上一阶段选中的需要整理的Region集合中存活的对象移到一个新的Region中(这个行为就叫做Relocate,即重新安置对象),如上图所示。Relocate动作完成后,原来占用的Region就能马上回收并被用于接下来的对象分配。细心的同学可能有疑问了,这就完了?Relocate后对象地址都发生变化了,应用程序还怎么正常操作这些对象呢?这就靠接下来会详细说明的Load Barrier了。Single Generation单代,即ZGC没有分代。我们知道以前的垃圾回收器

7、之所以分代,是因为源于“大部分对象朝生夕死”的假设,事实上大部分系统的对象分配行为也确实符合这个假设。那么为什么ZGC就不分代呢?因为分代实现起来麻烦,作者就先实现出一个比较简单可用的单代版本。用符合我们国情的话来解释,大概就是说:工作量太大了,人力又不够,老板,先上个1.0版本吧!Region Based这一点和G1一样,都是基于Region设计的垃圾回收器,ZGC中的Region也被称为ZPages,ZPages被动态创建,动态销毁。不过,和G1稍微有点不同的是,G1的每个Region大小是完全一样的,而ZGC的Region大小分为3类:2MB,32MB,N2MB,如此一来,灵活性就更好了

8、:Partial Compaction部分压缩,这一点也很G1类似。以前的ParallelOldGC,以及CMS GC在压缩Old区的时候,无论Old区有多大,必须整体进行压缩(CMS GC默认情况下只是标记清除,只会发生FGC时才会采用Mark-Sweep-Compact对Old区进行压缩),如此一来,Old区越大,压缩需要的时间肯定就越长,从而导致停顿时间就越长。而G1和ZGC都是基于Region设计的,在回收的时候,它们只会选择一部分Region进行回收,这个回收过程采用的是Mark-Compact算法,即将待回收的Region中存活的对象拷贝到一个全新的Region中,这个新的Regi

9、on对象分配就会非常紧凑,几乎没有碎片。垃圾回收算法这一点上,和G1是一样的。NUMA-awareNUMA对应的有UMA,UMA即Uniform Memory Access Architecture,NUMA就是Non Uniform Memory Access Architecture。UMA表示内存只有一块,所有CPU都去访问这一块内存,那么就会存在竞争问题(争夺内存总线访问权),有竞争就会有锁,有锁效率就会受到影响,而且CPU核心数越多,竞争就越激烈。NUMA的话每个CPU对应有一块内存,且这块内存在主板上离这个CPU是最近的,每个CPU优先访问这块内存,那效率自然就提高了:服务器的NU

10、MA架构在中大型系统上一直非常盛行,也是高性能的解决方案,尤其在系统延迟方面表现都很优秀。ZGC是能自动感知NUMA架构并充分利用NUMA架构特性的。Colored PointersColored Pointers,即颜色指针是什么呢?如下图所示,ZGC的核心设计之一。以前的垃圾回收器的GC信息都保存在对象头中,而ZGC的GC信息保存在指针中。每个对象有一个64位指针,这64位被分为:o 18位:预留给以后使用;o 1位:Finalizable标识,次位与并发引用处理有关,它表示这个对象只能通过finalizer才能访问;o 1位:Remapped标识,设置此位的值后,对象未指向relocat

11、ion set中(relocation set表示需要GC的Region集合);o 1位:Marked1标识;o 1位:Marked0标识,和上面的Marked1都是标记对象用于辅助GC;o 42位:对象的地址(所以它可以支持242=4T内存):通过对配置ZGC后对象指针分析我们可知,对象指针必须是64位,那么ZGC就无法支持32位操作系统,同样的也就无法支持压缩指针了(CompressedOops,压缩指针也是32位)。Load Barriers这个应该翻译成读屏障(与之对应的有写屏障即Write Barrier,之前的GC都是采用Write Barrier,这次ZGC采用了完全不同的方案)

12、,这个是ZGC一个非常重要的特性。在标记和移动对象的阶段,每次从堆里对象的引用类型中读取一个指针的时候,都需要加上一个Load Barriers。那么我们该如何理解它呢?看下面的代码,第一行代码我们尝试读取堆中的一个对象引用obj.fieldA并赋给引用o(fieldA也是一个对象时才会加上读屏障)。如果这时候对象在GC时被移动了,接下来JVM就会加上一个读屏障,这个屏障会把读出的指针更新到对象的新地址上,并且把堆里的这个指针“修正”到原本的字段里。这样就算GC把对象移动了,读屏障也会发现并修正指针,于是应用代码就永远都会持有更新后的有效指针,而且不需要STW。那么,JVM是如何判断对象被移动

13、过呢?就是利用上面提到的颜色指针,如果指针是Bad Color,那么程序还不能往下执行,需要slow path,修正指针;如果指针是Good Color,那么正常往下执行即可:这个动作是不是非常像JDK并发中用到的CAS自旋?读取的值发现已经失效了,需要重新读取。而ZGC这里是之前持有的指针由于GC后失效了,需要通过读屏障修正指针。后面3行代码都不需要加读屏障:Object p = o这行代码并没有从堆中读取数据;o.doSomething()也没有从堆中读取数据;obj.fieldB不是对象引用,而是原子类型。正是因为Load Barriers的存在,所以会导致配置ZGC的应用的吞吐量会变低

14、。官方的测试数据是需要多出额外4%的开销:那么,判断对象是Bad Color还是Good Color的依据是什么呢?就是根据上一段提到的Colored Pointers的4个颜色位。当加上读屏障时,根据对象指针中这4位的信息,就能知道当前对象是Bad/Good Color了。扩展阅读:既然低42位指针可以支持4T内存,那么能否通过预约更多位给对象地址来达到支持更大内存的目的呢?答案肯定是不可以。因为目前主板地址总线最宽只有48bit,4位是颜色位,就只剩44位了,所以受限于目前的硬件,ZGC最大只能支持16T的内存,JDK13就把最大支持堆内存从4T扩大到了16T。ZGC tuning启用ZG

15、C比较简单,设置JVM参数即可:-XX:+UnlockExperimentalVMOptions-XX:+UseZGC。调优也并不难,因为ZGC调优参数并不多,远不像CMS那么复杂。它和G1一样,可以调优的参数都比较少,大部分工作JVM能很好的自动完成。下图所示是ZGC可以调优的参数:下面对部分参数进行更加详细的说明。o UseNUMAZGC默认是开启支持NUMA的,不过,如果JVM探测到系统绑定的是CPU子集,就会自动禁用NUMA。我们可以通过参数-XX:+UseNUMA显示启动,或者通过参数-XX:-UseNUMA显示禁用。如果运行在NUMA服务器上,并且设置-XX:+UseNUMA,那对

16、性能提升是显而易见的。o UseLargePages配置ZGC使用large page通常就会得到更好的性能,比如在吞吐量、延迟、启动时间等方面。而且没有明显的缺点,除了配置过程复杂一点。因为它需要root权限,这也是默认并没有开启使用large page的原因。o ConcGCThreadsZGC是一个并发垃圾收集器,那么并发GC线程数就非常重要了。如果设置并发GC线程数越多,意味着应用线程数就会越少,这肯定是非常不利于应用系统稳定运行的。这个参数ZGC能自动设置,如果没有十足的把握。最好不要设置这个参数。o ParallelGCThreads这是个并行线程数,与上一个参数ConcGCThr

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 中学教育 > 教学课件 > 初中课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号