Go1.6与JVM CMS的垃圾回收对比
2016-04-13 15:03
232 查看
自从Go1.5引入了真正的并发GC后, Go1.6进一步进行了优化,使得Go在上百G级的堆大小时依然能将STW时间控制在20ms以内:
而Java8的G1收集器,默认参数下在100G以上的heap下,会造成秒级的STW。虽然可以通过
初始标记
并发标记
重新标记
并发清除
其中1, 3 是需要STW的阶段,CMS的停顿也是由这2个阶段引发的。Go1.5中的CMS也分为这些阶段,其中1, 3同样需要STW。那为什么Go会停顿时间更少呢?原因是,Go的CMS在第3阶段并不是挂起所有goroutine,而是轮流挂起。如此一来,3阶段就不会造成整个程序的停顿,从而就没有算入到STW时间之中。
到目前为止,Go的运行效率并没有因为执行的是本地机器码而体现出比Java更好的性能优势,我想这并不怪go, 而是JVM在JIT的帮助下其性能已经非常好了。虽然如此,Go的优化空间会比JVM更大。相信未来Go的性能会不断提升,终究会超过JVM。
而Java8的G1收集器,默认参数下在100G以上的heap下,会造成秒级的STW。虽然可以通过
-XX:MaxGCPauseMillis调整,但是是以牺牲大量吞吐量为代价。这里浅析一下Go能做到比G1更短的STW的原因。
轮流挂起协程
JVM的CMS收集器在工作时,大致分为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。
相关文章推荐
- Java 6 JVM参数选项大全(中文版)
- SQLSERVER 中GO的作用详解
- 深入解析JVM对dll文件和对类的装载过程
- 在Go语言程序中使用gojson来解析JSON格式文件
- 举例详解Go语言中os库的常用函数用法
- Go语言中函数的参数传递与调用的基本方法
- 深入解析Go语言的io.ioutil标准库使用
- GO语言的IO方法实例小结
- Go语言的os包中常用函数初步归纳
- Go语言中数组的基本用法演示
- Java虚拟机JVM性能优化(二):编译器
- Java程序员必须知道的5个JVM命令行标志
- GO语言类型转换和类型断言实例分析
- 深入解析Go语言编程中的递归使用
- 初步解读Golang中的接口相关编写方法
- Go语言实现的最简单数独解法
- 详解Golang编程中的常量与变量
- Go实现比较时间大小
- 深入剖析Go语言编程中switch语句的使用
- 简单讲解Go程序中使用MySQL的方法