golang垃圾回收简介


垃圾回收的核心就是标记出哪些内存还在使用中(即被引用到),哪些内存不再使用了(即未被引用),把未被引用的内存回收掉,以供后续内存分配时使用。

垃圾回收

常见的垃圾回收算法:

  • 引用计数:对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1;当引用计数器为0时回收该对象。
    • 优点:对象可以很快的被回收,不会出现内存耗尽或达到某个阀值时才回收。
    • 缺点:不能很好的处理循环引用,而且实时维护引用计数,也有一定的代价。
    • 代表语言:Python、PHP、Swift
  • 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记为”被引用”,没有被标记的进行回收。
    • 优点:解决了引用计数的缺点。
    • 缺点:需要STW,即要暂时停掉程序运行。
    • 代表语言:Golang(其采用三色标记法)
  • 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,而短的放入新生代,不同代有不同的回收算法和回收频率。
    • 优点:回收性能好
    • 缺点:算法复杂
    • 代表语言:JAVA

go垃圾回收

垃圾回收开始时从root对象开始扫描,把root对象引用的内存标记为“被引用”(需递归处理指针);全部标记完后,未标记的全部标识为未分配。

在span结构中有分配内存的位标记:
gc-mark

gcmarkBits记录每块内存标记情况,其结构与allocaBits完全一样;标记结束时,将allocBits指向gcmarkBits,gcmarkBits在下次标记时重新分配。

三色标记法(回收过程中三种状态):

  • 灰色:对象还在标记队列中等待;
  • 黑色:对象已被标记(gcmarkBits对应位为1)
  • 白色:对象未被标记(gcmarkBits对应位为0),会被GC回收掉。

回收优化

STW(StopTheWorld)就是停掉所有的goroutine,专心做垃圾回收,待垃圾回收结束后再恢复goroutine。

写屏障(Write Barrier):是让goroutine与GC同时运行的手段;在GC特定时机开启,开启后指针传递时会把指针标记(本轮不回收);

辅助GC(Mutator Assist):GC执行过程中,若goroutine需要分配内存,则让此goroutine参与一部分GC的工作。

触发时机

当内存分配量达到阈值:
阀值 = 上次GC内存分配量 * 内存增长率

内存增长率由GOGC控制,默认为100,即内存扩大一倍时启动GC。

定期触发:默认情况下,最长2分钟触发一次GC。

runtime.GC(),可手动触发GC。

逃逸分析

逃逸分析(Escape analysis)是指由编译器决定内存分配位置;编译器根据对象是否被函数外部引用决定是否逃逸:

  • 若函数外部没有引用,优先放在栈中(大对象,超过栈存储能力时,会被放到堆中);
  • 若函数外部存在引用,必定放在堆中;

函数参数为interface类型,编译期间很难确定具体类型,也会产生逃逸;闭包中引用的局部变量也会产生逃逸;

  • 栈上分配内存比在堆中分配内存有更高的效率
  • 栈上分配的内存不需要GC处理
  • 堆上分配的内存使用完毕会交给GC处理
  • 逃逸分析目的是决定内分配地址是栈还是堆
  • 逃逸分析在编译阶段完成

传递指针可以减少底层值的拷贝,可以提高效率,但是如果拷贝的数据量小,由于指针传递会产生逃逸,可能会使用堆,也可能会增加GC的负担,所以传递指针不一定是高效的。

代码优化

为提高性能,需要减少对象的分配(增加重用,降低GC压力):

  • 减少对象分配:
    • 尽量重用对象;
    • 当有很多小对象时,可考虑封装成一个大的对象(通过struct组合对象,GC在扫描时,只需判断整个对象是否有效即可);
    • slice与map等预分配内存;
  • string与byte[]间转换时,会涉及到内存的重新分配与数据复制,尽量减少;
  • 避免大量字符串连接操作(通过+连接):
    • fmt.Sprintf:方便拼接字符串;
    • strings.Join:方便串联字符串数组;
    • strings.Builder:方便字符串连接,尽量预分配容量;
  • 切片尽量预分配容量:减少append过程中的自动增长引起的内存重分配与数据复制;
  • 及时清理(通过defer关闭句柄等);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值