Go深度学习

本文章有引用部分

垃圾回收原理

GC实现原理

常用的垃圾回收算法

  • 引用计数:对每个对象维护一个计数,当引用该对象的对象被销毁时,引用计数减1;当引用计数器为0时,就是回收该对象的时候到了。

  • 优点:对象可以很快的被回收,不会出现内存耗尽或达到某个阈值时才被回收。

  • 缺点:不能很好的处理循环引用,而且实时的维护计数,也是需要一定的代价。

  • 代表语言:python、php、swift、

  • 标记-清除:从根变量开始遍历所有引用的对象,引用的对象被标记为“被引用”,没有被标记的进行回收。

  • 优点:解决了引用计数的缺点,不用维护一个实时的计数,节约了资源。

  • 缺点:需要STW(Stop-The-World机制),暂时停掉程序运行。

  • 代表语言:Golang(三色标记法)

  • 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,而短的放入新生代,不同代有不同的回收算法和回收频率。

  • 优点:回收性能好

  • 算法比较复杂

  • 代表语言:java

前言

前面说完几个常用的回收算法,脑子里还是懵的,所以特意去百度了很多知识博文,大概阐述一下自己的理解,有不对的地方,欢迎大家指出来。

因为最近一年完全用的Go语言,java这些都好久没用了,所以本文暂时只对Go的Gc做了一些阐述,后续空闲了会再去看看java的jvm垃圾回收
1.golang回收原理

前面也说了,golang的垃圾回收算法是三色标记法。简单来说就是标记并将内存分为"正在使用“和"未被使用",把”未被使用“的内存清理掉,以供后续内存的分配使用。

下图展示了一个简单地内存标记情况:

在这里插入图片描述

垃圾回收开始的时候,会从root对象开始扫描,把root对象指针指向的内存块位置标记为“被引用”,当全部递归标记完以后,就只留下已被标记的内存块,没有被标记的则表示“未被引用”,进行垃圾回收掉(我理解的是,垃圾回收的开始,就是递归标记结束后马上进行,一直往复循环)。

2.三色标记法

垃圾回收之前会对内存块进行标记,则还需要一个存储待标记对象的标记队列。整个过程大概是:

1.从标记队列中取出对象

2.对对象的引用状态进行标记

3.把对象引用到的其他对象再放入队列中

我们所说的三色标记法并不是说用三中颜色来标记,只是对垃圾回收过程中对象的三种状态进行的一个抽象出来的概念。

  • 灰色:对象在标记队列中等待

  • 黑色:对象已被标记,gcmarkBits标记为1

  • 白色:对象未被标记,gcmarkBits标记为0,待标记完后,该对象马上被清理掉

Example

白色:对象未被标记,gcmarkBits标记为0,待标记完后,该对象马上被清理掉

Example

当前内存中有A~F一共6个对象,根对象a,b本身为栈上分配的局部变量,根对象a、b分别引用了对象A和对象B, 而B对象又引用了对象D,则GC开始前各对象的状态如下图所示:在这里插入图片描述
初始状态下所有对象都是白色的未被标记转态。
此时从跟对象a、b开始扫描:在这里插入图片描述
由于根对象引用了A和B对象,那么A、B变为灰色对象,接下来就开始分析灰色对象,分析A时,因为A没有引用其他对象很快就被标记变为黑色;因为B引用了D,所以B转变为黑色的同时将D转换为灰色,进行接下来的分析。如图所示:在这里插入图片描述
此时灰色对象只有D,而D并没有引用其他对象了,所以D直接被标记转为黑色。标记过程结束。在这里插入图片描述
最终,被标记的A、B、D对象会被保存下来,其他的没有被标记的对象会马上被垃圾回收调。

Golang垃圾回收的缺陷

  • stop the word
    对于垃圾回收来说,在整个回收的过程中也需要控制内存的变化,否则回收过程中指针传递会引起内存引用关系变化,如果错误的回收了正在使用的内存,将会导致系统崩溃的情况产生。

example:

在这里插入图片描述
在A被标记完以后,A变为黑色,A又引用了C,但是此时A已经被标黑,此时C作为白色将不可能再变为灰色,那么垃圾回收的时候C会被回收掉,此时A对象还在引用着C,会导致空指针的情况出现。

针对这样的问题,Golang中的STW就是停掉所有的gorounting,专心做垃圾回收,当垃圾回收完毕以后再恢复gorounting。也正是这样,垃圾回收的时间长短也直接的影响了整个应用的执行性能,特别是对于一些Web应用来说是不可接收的,这也是广受诟病的原因之一。

优化垃圾回收

既然我们知道了垃圾回收会影响程序的执行性能,那么如何优化,能让我们的性能更加的好。

  • 1.写屏障(Write Barrier)
    既然SWT的方式是GC的同时停掉gorounting,那么写屏障的目的就是为了让GC能与gorounting同时运行。
    写屏障就是类似一种开关,在GC的特定时间开启,开启后指针传递时会把指针标记,那么本轮的GC就不会回收该对象。
    GC过程中如果有新的对象产生,会马上被标记,所以也不会在本轮GC回收掉。
  • 2.环境变量GOGC控制触发GC
    每次内存分配时都会检查当前内存分配量是否已达到阀值,如果达到阀值则立即启动GC。
    阀值 = 上次GC内存分配量 * 内存增长率
    内存增长率由环境变量GOGC控制,默认为100,即每当内存扩大一倍时启动GC。
  • 3.手动触发GC
    程序代码中也可以使用runtime.GC()来手动触发GC。这主要用于GC性能测试和统计。
  • 4.定时GC
    默认情况下,最长2分钟触发一次GC
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值