图解Golang的GC算法
虽然Golang的GC自打一开始,就被人所诟病,但是经过这么多年的发展,Golang的GC已经改善了非常多,变得非常优秀了。
以下是Golang GC算法的里程碑:
- v1.1 STW
- v1.3 Mark STW, Sweep 并行
- v1.5 三色标记法
- v1.8 hybrid write barrier
经典的GC算法有三种:引用计数(reference counting)、标记-清扫(mark & sweep)、复制收集(Copy and Collection)。
Golang的GC算法主要是基于标记-清扫(mark and sweep)算法,并在此基础上做了改进。因此,在此主要介绍一下标记-清扫(mark and sweep)算法,关于引用计数(reference counting)和复制收集(copy and collection)可自行百度。
标记-清扫(Mark And Sweep)算法
此算法主要有两个主要的步骤:
- 标记(Mark phase)
- 清除(Sweep phase)
第一步,找出不可达的对象,然后做上标记。
第二步,回收标记好的对象。
操作非常简单,但是有一点需要额外注意:mark and sweep算法在执行的时候,需要程序暂停!即stop the world。
也就是说,这段时间程序会卡在哪儿。故中文翻译成卡顿。
我们来看一下图解:
开始标记,程序暂停。程序和对象的此时关系是这样的:

然后开始标记,process找出它所有可达的对象,并做上标记。如下图所示:

标记完了之后,然后开始清除未标记的对象:

然后垃圾清除了,变成了下图这样。

最后,停止暂停,让程序继续跑。然后循环重复这个过程,直到process生命周期结束。
标记-清扫(Mark And Sweep)算法存在什么问题?
标记-清扫(Mark And Sweep)算法这种算法虽然非常的简单,但是还存在一些问题:
- STW,stop the world;让程序暂停,程序出现卡顿。
- 标记需要扫描整个heap
- 清除数据会产生heap碎片
这里面最重要的问题就是:mark-and-sweep 算法会暂停整个程序。
Go是如何面对并这个问题的呢?
三色并发标记法
我们先来看看Golang的三色标记法的大体流程。
首先:程序创建的对象都标记为白色。

gc开始:扫描所有可到达的对象,标记为灰色

从灰色对象中找到其引用对象标记为灰色,把灰色对象本身标记为黑色

监视对象中的内存修改,并持续上一步的操作,直到灰色标记的对象不存在

此时,gc回收白色对象。

最后,将所有黑色对象变为白色,并重复以上所有过程。

好了,大体的流程就是这样的,让我们回到刚才的问题:Go是如何解决标记-清除(mark and sweep)算法中的卡顿(stw,stop the world)问题的呢?
gc和用户逻辑如何并行操作?
标记-清除(mark and sweep)算法的STW(stop the world)操作,就是runtime把所有的线程全部冻结掉,所有的线程全部冻结意味着用户逻辑是暂停的。这样所有的对象都不会被修改了,这时候去扫描是绝对安全的。
Go如何减短这个过程呢?标记-清除(mark and sweep)算法包含两部分逻辑:标记和清除。
我们知道Golang三色标记法中最后只剩下的黑白两种对象,黑色对象是程序恢复后接着使用的对象,如果不碰触黑色对象,只清除白色的对象,肯定不会影响程序逻辑。所以:清除操作和用户逻辑可以并发。
标记操作和用户逻辑也是并发的,用户逻辑会时常生成对象或者改变对象的引用,那么标记和用户逻辑如何并发呢?
process新生成对象的时候,GC该如何操作呢?不会乱吗?
我们看如下图,在此状态下:process程序又新生成了一个对象,我们设想会变成这样:

但是这样显然是不对的,因为按照三色标记法的步骤,这样新生成的对象A最后会被清除掉,这样会影响程序逻辑。
Golang为了解决这个问题,引入了写屏障这个机制。
写屏障:该屏障之前的写操作和之后的写操作相比,先被系统其它组件感知。
通俗的讲:就是在gc跑的过程中,可以监控对象的内存修改,并对对象进行重新标记。(实际上也是超短暂的stw,然后对对象进行标记)
在上述情况中,新生成的对象,一律都标位灰色!
即下图:

那么,灰色或者黑色对象的引用改为白色对象的时候,Golang是该如何操作的?
看如下图,一个黑色对象引用了曾经标记的白色对象。

这时候,写屏障机制被触发,向GC发送信号,GC重新扫描对象并标位灰色。

因此,gc一旦开始,无论是创建对象还是对象的引用改变,都会先变为灰色。
更多精彩内容,请关注我的微信公众号 互联网技术窝 或者加微信共同探讨交流:

图解Golang的GC算法的更多相关文章
- 图解golang内存分配机制 (转)
一般程序的内存分配 在讲Golang的内存分配之前,让我们先来看看一般程序的内存分布情况: 以上是程序内存的逻辑分类情况. 我们再来看看一般程序的内存的真实(真实逻辑)图: Go的内存分配核心思想 G ...
- 动图图解GC算法 - 让垃圾回收动起来!
原创:码农参上(微信公众号ID:CODER_SANJYOU),欢迎分享,转载请保留出处. 提到Java中的垃圾回收,我相信很多小伙伴和我一样,第一反应就是面试必问了,你要是没背过点GC算法.收集器什么 ...
- 46张PPT讲述JVM体系结构、GC算法和调优
本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述.(内嵌iframe,建议使用电脑浏览) 好东西当然要分享,PPT已上传可供下载 ...
- JVM学习(4)——全面总结Java的GC算法和回收机制
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 一些JVM的跟踪参数的设置 Java堆的分配参数 -Xmx 和 –Xms 应该保持一个什么关系,可以让系统的 ...
- jvm系列(三):java GC算法 垃圾收集器
GC算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计 ...
- JVM GC算法 CMS 详解(转)
前言 CMS,全称Concurrent Low Pause Collector,是jdk1.4后期版本开始引入的新gc算法,在jdk5和jdk6中得到了进一步改进,它的主要适合场景是对响应时间的重要性 ...
- JVM内存管理------GC算法精解(五分钟教你终极算法---分代搜集算法)
引言 何为终极算法? 其实就是现在的JVM采用的算法,并非真正的终极.说不定若干年以后,还会有新的终极算法,而且几乎是一定会有,因为LZ相信高人们的能力. 那么分代搜集算法是怎么处理GC的呢? 对象分 ...
- JVM内存管理------GC算法精解(复制算法与标记/整理算法)
本次LZ和各位分享GC最后两种算法,复制算法以及标记/整理算法.上一章在讲解标记/清除算法时已经提到过,这两种算法都是在此基础上演化而来的,究竟这两种算法优化了之前标记/清除算法的哪些问题呢? 复制算 ...
- JVM内存管理------GC算法精解(五分钟让你彻底明白标记/清除算法)
相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑话说前面哦,这篇文章应该能让各位彻底理解标记/清除算法,不过倘若各位猿友不能在五分钟内 ...
随机推荐
- EF core2.1+MySQL报错'Void Microsoft.EntityFrameworkCore.Storage.Internal.RelationalParameterBuilder..ctor(Microsoft.EntityFrameworkCore.Storage.IRelationalTypeMapper)
一.使用.net core 2.0 EF mysql 运行一直报错如下: An unhandled exception occurred while processing the request. M ...
- upload三种上传方式(上)---Servlet---post---commons-fileupload.1.2.1.jar方式请求上传文件
上传前进行的配置选项: 1.在下方的Servers中,右键你的tomcat--open,选中下面两个配置. 第一个:Serve modules without publishing 作用:tomcat ...
- PHP简单的长文章分页教程 附源码
PHP简单的长文章分页教程 附源码.本文将content.txt里的内容分割成3页,这样浏览起来用户体验很好. 根据分页参数ipage,获取对应文章内容 include('page.class.php ...
- MongoDB(3)--Java 操作 MongoDB 的 API
引入mongoDb 依赖 <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-j ...
- Shell 编程中,在循环里使用ssh免密远程执行命令的注意事项
前提:给自己机器配置ssh免密登录#!/bin/bashcat << 'EOD' > list1234EOD while read linedo if ssh myname@127. ...
- mysql-day1
-- 数据库的操作 -- 链接数据库 mysql -uroot -p mysql -uroot -pmysql -- 退出数据库 exit/quit/ctrl+d -- sql语句最后需要有分号;结尾 ...
- java枚举变量反解析用法
最近常常有一些项目需要给枚举设值一个int值,以及对int值进行反解析出枚举类型,代码如下: public enum MatchResultEnum { /** * 赢 */ WIN(0), /** ...
- rest_famework 增删改查初第二阶段(中级,此阶段是优化初级阶段的代码)的使用
url: re_path('authors/$', views.AuthorView.as_view()),re_path('authors/(\d+)/$', views.AuthorDetailV ...
- MTK6261初始化待机流程
- python框架django-web层
1.demo 命令行:django-admin startproject HelloWorld 命令执行成功后会根据模版生产一个django项目 然后通过 命令:python3 manage.py r ...