用户程序通过内存分配器(Allocator)在堆上申请内存,而垃圾收集器(Collector)负责回收堆上的内存空间,内存分配器和垃圾收集器共同管理程序中的堆内存空间。

基本概念

垃圾分类

  • 语义垃圾:也就是内存泄漏,指的是从语法上可达的对象,也就是被其他对象引用的,但是从语义上来讲是垃圾。这类垃圾,垃圾回收是不管的
  • 语法垃圾:从语法上是不可达的对象,也就是没有对象引用了,这些垃圾是垃圾回收重点照顾的对象

垃圾回收算法

常见的垃圾回收算法:

  • 引用计数:

    某个对象的根引用计数变为0时,其所有节点均需被回收

  • 标记压缩:

    存活对象移动到一起,有效解决内存碎片问题

  • 复制算法:

    将所有正在使用的对象从From空间复制到To空间,堆利用率只有一半,也能解决内存碎片问题

  • 标记清除:

    标记垃圾对象,然后再清除。解决不了内存碎片问题,需要与能尽量避免内存碎片的内存分配器使用,如tcmalloc

标记清除

标记清除算法是最常见的垃圾收集算法,标记清除收集器是跟踪式垃圾收集器,其执行过程可以分为标记、清除两个阶段:

  1. 标记阶段:从根对象出发查找并标记堆中所有存活的对象
  2. 清除阶段:遍历堆中的全部对象,回收未被标记的垃圾对象并将回收的内存加入空闲链表

传统的标记清除算法,垃圾收集器从垃圾收集的根对象出发,递归遍历这些对象指向的子对象并将所有可达的对象标记成存活。标记结束后,垃圾收集器会依次遍历堆中的对象并清除其中的垃圾,整个过程需要标记对象的存活状态,所以用户程序在垃圾收集的过程中不能执行,也就是常说的STW(Stop The World)

三色抽象

为了解决原始标记清除算法带来的长时间STW,大部分追踪式垃圾收集器都会实现三色标记算法的变种以缩短STW的时间

三色标记算法将程序中的对象分成白色、黑色、灰色:

  • 白色对象:潜在的垃圾,也就是没有被扫到的对象,其内存可能会被垃圾收集器回收
  • 黑色对象:活跃的对象,包括不存在任何引用外部指针的对象以及从根对象可达的对象
  • 灰色对象:活跃的对象,因为存在指向白色对象的外部指针,垃圾收集器会扫描这些对象的子对象

标记过程:

垃圾收集器开始工作的时候,不存在任何黑色对象,根对象会被标记成灰色,垃圾收集器只会从灰色对象集合中取出对象开始扫描,当灰色集合中不存在任何对象时,标记就会结束。

大致工作原理:

  1. 从灰色对象的集合中选择一个灰色对象并将其标记成黑色
  2. 将黑色对象指向的所有对象都标记成灰色,保证该对象和被该对象引用的对象都不会被回收
  3. 重复上述两个步骤直到不存在灰色对象

当三色标记结束后,应用程序的堆中就不存在任何灰色对象,我们只能看到黑色的存活对象以及白色的垃圾对象,垃圾收集器可以回收这些白色的垃圾。

缺陷:

由于用户程序可能在标记执行的过程中修改对象的指针,所以三色标记清除算法本身是不可以并发或者增量执行的,仍需要STW。如果本来不应该被回收的对象被回收了,这在内存管理中是非常严重的错误,这种错误称为悬挂指针,也就是指针没有指向特定类型的合法对象,影响了内存的安全性,想要并发或者增量标记对象就需要使用屏障技术。

屏障技术

内存屏障技术是一种屏障指令,可以让CPU或编译器在执行内存相关的操作时遵循特定的约束,目前多数的现代处理器都会乱序执行指令以最大化性能,但是该技术能够保证内存操作的顺序性,在内存屏障前执行的操作一定会先于内存屏障后执行的操作。想在并发或增量的标记算法中保证正确性,需要达到两种三色不变性的其中一种。

三色不变性:

  • 强三色不变性:黑色对象不会指向白色对象,只会指向灰色对象或者黑色对象
  • 弱三色不变性:黑色对象指向的白色对象必须包含一条从灰色对象经由多个白色对象的可达路径

屏障技术分为读屏障和写屏障,但是由于读屏障需要在读操作中加入代码片段,所以对用户程序的性能影响较大。解析一下go语言中使用的两种写屏障技术,插入写屏障和删除写屏障。

插入写屏障(DIJKSTRA)

writePointer(slot, ptr):
shade(ptr)
*slot = ptr

每当要执行*slot = ptr时,会先执行写屏障通过shade函数尝试改变指针颜色。如果ptr指针是白色,那么会将该对象设置成灰色。

这张图中可以看到,在一次正常的标记过程中,发生了用户程序修改了指针引用(或者新插入了一个引用关系)的情况,如果我们采用 插入写屏障 我们就需要将新指向的对象标为灰色,以此保证强三色不变性。(对于新指向的对象来说,属于被插入一个引用,所以叫插入写屏障)

在插入写屏障中,我们的标记过程变成(关键第2步):

  1. 基本标记流程不变,我们快进到垃圾收集器将根对象指向A对象标记成黑色,并将A对象指向的对象B标记成灰色。
  2. 这时用户程序修改A对象的指针,将原本A对象指向B对象的指针指向C对象,这个时候就会触发写屏障将C对象标记为灰色,避免被错误回收。
  3. 垃圾收集器依次遍历程序中的其他灰色对象,将他们分别标记成黑色

删除写屏障(YUASA)

writePointer(slot, ptr)
shade(*slot)
*slot = ptr

删除写屏障会在老对象的引用被删除的时候,将白色的老对象涂成灰色,这样就可以保证弱三色不变性,老对象引用的下游对象一定可以被灰色对象引用。

使用删除写屏障技术的垃圾收集器和用户程序交替运行的场景中的标记过程:

  1. 垃圾收集器将根对象指向A对象标记成黑色并将A对象指向的对象B标记成灰色
  2. 如果这时用户程序将B指向C的指针删除,那么C触发删除写屏障,由于C是白色,所以被涂成灰色
  3. 垃圾收集器依次遍历程序中的其他灰色对象,将他们分别标记成黑色

第二步触发删除写屏障的着色,因为删除了B指向C的指针,所以C和D分别违反强三色不变性和弱三色不变性,着色后保证了三色不变性,避免悬挂指针。

简单来说就是,在改变指针指向的时候,原来指向的那个对象是白色的话就要变成灰色,以此保证弱三色不变性。(对于老对象来说,引用关系被解除了,所以叫删除写屏障)

增量和并发

两种策略优化垃圾收集器不会以为回收垃圾导致长时间STW:

  • 增量垃圾收集:增量得标记和清除垃圾,降低应用程序暂停的最长时间
  • 并发垃圾手机:利用多核的计算资源,在用户程序执行时并发标记和清除垃圾

由于两种方式都需要垃圾收集器与用户程序交替执行,所以需要配合屏障技术。

增量收集器

增量收集器将原本时间较长的暂停时间切分成多个更小的GC时间片。增量收集器需要配合三色标记法和屏障技术一起使用。将GC过程分段执行,虽然拉长了总的垃圾回收时间,但是减少了程序STW的时间。不过写屏障还是有些开销的。

并发收集器

利用多核优势,将GC过程与用户程序并行执行(大部分情况下),也是要配合屏障技术。

References

  1. https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-garbage-collector/
  2. https://spin.atomicobject.com/2014/09/03/visualizing-garbage-collection-algorithms/

GO的GC辣鸡回收(一)的更多相关文章

  1. JVM 辣鸡回收

    垃圾回收算法 标记清除法 先标记出需要回收的对象,然后一次性回收.缺点:会产生内存碎片,并且效率也不高. 标记压缩法 先标记出需要回收的对象,然后让存活对象向一端移动,移动的过程中进行回收辣鸡.避免了 ...

  2. JVM学习(4)——全面总结Java的GC算法和回收机制

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 一些JVM的跟踪参数的设置 Java堆的分配参数 -Xmx 和 –Xms 应该保持一个什么关系,可以让系统的 ...

  3. java: system.gc()和垃圾回收机制finalize

    System.gc()和垃圾回收机制前的收尾方法:finalize(收尾机制) 程序退出时,为每个对象调用一次finalize方法,垃圾回收前的收尾方法 System.gc() 垃圾回收方法 clas ...

  4. 关于GC进行垃圾回收的时机

    前言 今天查看一个同事的代码,发现代码中多处地方使用了GC.Collect()方法,我问他为什么这么做,他说感觉程序中定义了好多变量,怕GC回收不及时,用GC.Collect()可以手动掌控GC进行垃 ...

  5. GC(垃圾回收)

    Java程序的内存分配和回收都是由JRE在后台自动进行的.JRE会负责回收那些不再使用的内存,这种机制被称为垃圾回收GC.通常JRE会提供一条超级线程来进行检测和控制,一般都是在CPU空闲或内存不足时 ...

  6. 【转载】Java性能优化之JVM GC(垃圾回收机制)

    文章来源:https://zhuanlan.zhihu.com/p/25539690 Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我 ...

  7. JVM总括二-垃圾回收:GC Roots、回收算法、回收器

    JVM总括二-垃圾回收:GC Roots.回收算法.回收器 目录:JVM总括:目录 一.判断对象是否存活 为了判断对象是否存活引入GC Roots,如果一个对象与GC Roots没有直接或间接的引用关 ...

  8. JVM学习(4)——全面总结Java的GC算法和回收机制---转载自http://www.cnblogs.com/kubixuesheng/p/5208647.html

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 一些JVM的跟踪参数的设置 Java堆的分配参数 -Xmx 和 –Xms 应该保持一个什么关系,可以让系统的 ...

  9. Java性能优化之JVM GC(垃圾回收机制)

    Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.st ...

随机推荐

  1. P4494 [HAOI2018]反色游戏

    P4494 [HAOI2018]反色游戏 题意 给你一个无向图,图上每个点是黑色或者白色.你可以将一条边的两个端点颜色取反.问你有多少种方法每个边至多取反一次使得图上全变成白色的点. 思路 若任意一个 ...

  2. CF1032G Chattering

    CF1032G Chattering 题意 思路 对于每一个位置,它转移的范围是确定的. 对于一段可以走到的区间,我们可以求出区间中所有点再能走到区间范围. 于是这个就可以倍增进行转移. 如何快速求出 ...

  3. Receiver class com.mchange.v2.c3p0.impl.NewProxyResultSet does not define or inherit an implementation of the resolved method 'abstract boolean isClosed()' of interface java.sql.ResultSet.

    背景: Mayabtis+springboot项目,连接数据库发生异常 报错内容: java.lang.AbstractMethodError: Receiver class com.mchange. ...

  4. 深入刨析tomcat 之---第10篇 how tomcat works 第13章,Response 发送错误信息 sendError

    writedby 张艳涛 在浏览器中发送一个错误应用url 那么tomcat是如何发送错误的呢? 基本上是发送http 的response协议,分为两部分一部分是response设置头信息, 那么先分 ...

  5. frame window 和open 的关系

    建立一个如下的关系框架 windowA.html <!DOCTYPE html> <html lang="en"> <head> <met ...

  6. jQuery 两个日期时间相减

    var sDate='2016-10-31';var eDate='2016-10-10'var sArr = sDate.split("-");var eArr = eDate. ...

  7. Sunset靶机

    仅供个人娱乐 靶机信息 https://www.vulnhub.com/entry/sunset-sunrise,406/ 一.主机探测 二.信息收集 nmap -sS -sV -T5 -A -p- ...

  8. html页面自动跳转

    <script type="javascrpit"> var url='';//需要跳转的页面 var search = window.location.search; ...

  9. linux中的防火墙netfilter iptables

    目录 一.Linux防火墙基础 1.1 ptables的表.链结构 1.2 数据包控制的匹配流程 二.编写防火墙规则 1.iptables的安装 2.1 基本语法.控制类型 一般在生产环境中设置网络型 ...

  10. Android音视频开发(1):H264 基本原理

    前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...