Go1.6与JVM CMS的垃圾回收对比

tracker_w · · 3298 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

自从Go1.5引入了真正的并发GC后, Go1.6进一步进行了优化,使得Go在上百G级的堆大小时依然能将STW时间控制在20ms以内:
这里写图片描述

而Java8的G1收集器,默认参数下在100G以上的heap下,会造成秒级的STW。虽然可以通过-XX:MaxGCPauseMillis调整,但是是以牺牲大量吞吐量为代价。这里浅析一下Go能做到比G1更短的STW的原因。

轮流挂起协程

JVM的CMS收集器在工作时,大致分为4个阶段:

  1. 初始标记
  2. 并发标记
  3. 重新标记
  4. 并发清除

其中1, 3 是需要STW的阶段,CMS的停顿也是由这2个阶段引发的。Go1.5中的CMS也分为这些阶段,其中1, 3同样需要STW。那为什么Go会停顿时间更少呢?原因是,Go的CMS在第3阶段并不是挂起所有goroutine,而是轮流挂起。如此一来,3阶段就不会造成整个程序的停顿,从而就没有算入到STW时间之中。

Go触发GC的时机

Go的gc触发条件也与JVM的gc有很大区别。JVM通常是堆的使用到达某一阀值,或发生new操作失败时gc。而Go则是当从上次gc以来,新创建的对象大小等于上次gc以后存活下来的对象时触发gc. 这样,每次gc的压力就不会像JVM那么大,STW时间理所当然会短很多,但也牺牲了吞吐量。

Go比Java产生更少的内存垃圾

Go的对象(即struct类型)是可以分配在栈上的。Go会在编译时做静态逃逸分析(Escape Analysis), 如果发现某个对象并没有逃出当前作用域,则会将对象分配在栈上而不是堆上,从而减轻了GC压力。其实JVM也有逃逸分析,但与Go不同的是Java无法在编译时做这项工作,分析是在运行时完成的,这样做一是会占用更多的CPU时间,二是不可能会把所有未逃逸的对象都优化到栈中。

到目前为止,Go的运行效率并没有因为执行的是本地机器码而体现出比Java更好的性能优势,我想这并不怪go, 而是JVM在JIT的帮助下其性能已经非常好了。虽然如此,Go的优化空间会比JVM更大。相信未来Go的性能会不断提升,终究会超过JVM。


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:tracker_w

查看原文:Go1.6与JVM CMS的垃圾回收对比

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

3298 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传