高级语言垃圾回收思路和如何减少性能影响原理分析

前面几章内容
(一) go协程栈底层讲解
(二) go的堆内存结构分析
(三) 高级语言垃圾回收思路和如何减少性能影响原理分析

5. 高级语言垃圾回收的思路

现在我们遇到了下面的情况,当几个对象需要回收时,编译器内部时怎么做的,虽然不用程序员去直接操作它,但是知道一下底层原理对后续帮助也是不小的

在这里插入图片描述
这里垃圾回收的思路,有下面三种方式:

  1. 标记-清除
  2. 标记-整理
  3. 标记-复制

5.1 标记-清除

这种是最简单粗暴的方式

下面直接展示在go 中当里昂个对象需要回收时,用标记-清楚的方式时如何处理的
在这里插入图片描述
清楚结束的状态:
在这里插入图片描述
【注】:如果是别的语言可能有碎片的问题,但是Go 使用的span分级策略,没有了这种问题

5.2 标记-整理

同样当有两个对象需要进行垃圾回收时,使用标记-整理时的处理方式时怎么样的

初始状态:标记了需要删除的对象
在这里插入图片描述

标记-整理: 这里的当时是把后面的对象整理过来让整个堆内存的碎片化情况大大改善但是开销很大,会造成GC 卡顿(老版本的java用的这种,因为之前的数据量不大,影响相对小一点)
在这里插入图片描述

5.3 标记-复制

同上的场景:

初始状态:
在这里插入图片描述
标记-赋值: 这里的方式是把有用的复制到另一块达到了整理的效果,用时还非常短但是空间消耗大
在这里插入图片描述

5.4 在go 中使用的方式及原因

  1. Go因为堆内存结构的独特优势,选择最简单的标记-清除, 后面两种是java 在用
  2. 找到有引用的对象,剩下的就是没有引用(剩下的清楚就行了)

5.5 怎么标记(从哪里开始找需要回收的对象)

在程序中,有一些对象是不能被清除的,下面是具体例子

  1. 被栈上的指针引用
  2. 被全局变量指针引用
  3. 被寄存器中的指针引用
    上述变量被称为 Root Set (GC Root)
5.5.1 Root 节点进行广度优先搜索BFS

这种方法也叫可达性分析标记法

具体步骤用下面几幅图描述:

  1. 下面中格子是系统中一个一个栈空间
  2. 字母表示的不同的对象,字母之间边的情况是不同对象之间的关系
    在这里插入图片描述
  3. 开始进行BFS进行搜索
    在这里插入图片描述
  4. 下一步搜索,先标记,后清除(这里就是清除对象G和H)
    在这里插入图片描述

5.6 串行GC步骤

上面描述的垃圾回收是串行的,怎么理解呢,就是在扫描整个进程中的对象时,需要暂停其他所有协程,为什么,因为其他协程在运行时会影响这个垃圾回收机制的判断。
具体步骤是下面几步:

  1. Stop The World, 暂停所有其他协程
  2. 通过可达性分析,找到无用的堆内存
  3. 释放对内存
  4. 恢复所有其他协程

5.6 串行GC步骤引发的问题

STW 对性能影响大(暂停了其他协程,影响不必过多解释)

5.7 小结

  1. 从GC Root 出发,寻找被引用对象
  2. 没有被引用的就是无用对象
  3. 串行GC需要STW, 对性能影响大

6. go如何减少gc对性能的影响

通过对上面的例子进行分析,如果使用STW方式,对性能肯定是有很大影响的,这时就需要有一个减少gc对性能的影响的方法了

于是并发垃圾回收的方式就有了,难点在哪里呢,其实并发垃圾回收过程中 ,可以不难分析出难点在于标记阶段

6.1 三色标记法

  1. 黑色: 有用,已经分析扫描
  2. 灰色: 有用,还未分析扫描
  3. 白色: 暂时无用

6.2 常规步骤

  1. 初始状态
  2. 将灰色放入广度优先中队列中,进行下一步分析
    在这里插入图片描述
  3. BFS 搜索

在这里插入图片描述
4. 清除白色对象
5. 再次标记时,所有对象回复为白色
在这里插入图片描述

6.3 并发标记出现的问题(删除)(其他协程是没有停的)

  1. 在并发标记进行中
    在这里插入图片描述

  2. 业务: B指向C的指针释放

  3. 业务:E的一个指针成员指向了C
    在这里插入图片描述

  4. 继续扫描

  5. C被错误清除
    在这里插入图片描述

6.4 Yuasa 删除屏障

原理:

  • 并发标记时
  • 对指针释放的白色对象置灰

操作步骤:

  1. 并发标记初始状态
    在这里插入图片描述

  2. 分析BF 之前,业务: B指向C的指针释放
    在这里插入图片描述

  3. 删除屏障: 会强制C被置灰(只要释放了指针,强制置灰)
    在这里插入图片描述

  4. 业务: E的一个指针成员指向了C
    在这里插入图片描述

  5. 继续扫描
    在这里插入图片描述

  6. 继续扫描,这样C就不会被误删除
    在这里插入图片描述

特点:只要有用的对象就不会被误清理

删除屏障可以杜绝在GC标记中被释放的指针,被清理

6.5 并发标记问题(插入)

是指GC过程中只有插入过程,没有指针释放的过程(也就没有置灰的过程)
这时删除屏障没有起作用

出现问题步骤如下:

  1. 并发标记进行中, 标记前C已经是无用对象了
    在这里插入图片描述

  2. 业务:E的一个指针成员指向了C
    在这里插入图片描述

  3. 继续扫描
    在这里插入图片描述

  4. 继续扫描
    在这里插入图片描述

  5. 对象 C 被错误清除
    在这里插入图片描述

6.6 Dijkstra 插入屏障

为了解决上面的问题
Dijkstra 插入屏障原理: 在并发标记时,对指针新指向的白色对象置灰

操作步骤:

  1. 并发标记进行中, 标记前C已经是无用对象了
    在这里插入图片描述

  2. 业务:E的一个指针成员指向了C(插入屏障起效)
    在这里插入图片描述

  3. 继续扫描
    在这里插入图片描述

  4. 扫描结局,会发现没有之前的问题
    在这里插入图片描述

插入屏障可以杜绝在GC标记中被插入的指针,被清理(保证新增的依赖关系不会被清理)

6.7 混合屏障

在Go中是使用上述两种屏障,也就是说将上面两种方式混合起来使用

  1. 被删除的堆对象标记为灰色
  2. 被添加的堆对象标记为灰色

6.8 小结

  1. 并发垃圾回收的关键在于标记安全
  2. 混合屏障机制兼顾了安全与效率

7. 在实战中提高gc效率

在go中如何提高gc效率呢,可以分析下面集中方式

  1. 系统定时触发gc
  2. 用户显式触发gc
  3. 申请内存时触发gc

7.1 系统定时触发

  1. sysmon 定时检查
  2. 如果2分钟内没有过GC,会触发
  3. 谨慎调整(因为这里涉及更改系统设置)
    在这里插入图片描述
    2分钟;在runtime/proc.go 文件中

7.2 用户显式触发

  1. 用户调用runtime.GC 方法
  2. 并不推荐调用

7.3 申请内存时触发

  1. 给对象申请堆空间时,可能导致GC

7.4 GC 优化原则

尽量少在堆上产生垃圾

  1. 内存池化
  2. 减少逃逸(逃逸后变量在堆上)
  3. 使用空结构体

7.5内存池化

  1. 缓存性质的对象
  2. 频繁创建和删除
  3. 使用内存池,不GC

7.6 减少逃逸

  1. 逃逸会使原本在栈上的对象进入堆中
  2. fmt 包(在项目中少用,可以用log包)
  3. 返回了指针而不是拷贝

7.7 使用空结构体

  1. 空结构体指向一个固定地址
  2. 不占用堆空间
  3. 比如channel 传递空结构体

7.8 GC 分析工具

  1. go tool pprof
  2. go tool trace
  3. go build -gcflags = " -m"
  4. GODEBUG = " gctrace = 1" (简单粗暴)

7.9 工具演示

步骤:
配置环境变量
运行代码
在这里插入图片描述

7.10 小结

  1. GC主要由系统定时触发或者申请内存触发
  2. GC优化原则是减少在堆上产生垃圾
  3. 使用GC分析工具可以帮助分析GC问题

8. 总结

8.1 协程栈

  1. 协程栈记录了协程的执行现场
  2. Go协程栈位于Go堆内存上
  3. Go 使用参数拷贝传递
  4. 3种特殊情况下,变量可能会逃逸到堆上
  5. 1.14 以后,Go 使用连续栈,伸缩时直接使用新栈

8.2 堆内存结构

  1. Go模仿TCmalloc(C++的内存的结构),建立了自己的堆内存架构
  2. 使用heapArena 向操作系统申请内存
  3. 使用heapArena时,以mspan 为单位,防止碎片化
  4. mcentral 是mspan 们的中心索引
  5. mcache 记录了分配给各个P 的本地mspan
    在这里插入图片描述

8.3 堆内存分配

  1. Go将对象按照大小分为3种
  2. 微小对象使用mcache
  3. mcache中的mspan 填满后,与mcentral 交换新的
  4. mcentral 不足时,在heapArena 开辟新的mspan
  5. 大对象直接在heapArena 开辟新的mspan

8.4 堆内存回收(GC)

8.4.1 标记-清除 法

标记有用对象,清除无用对象

8.4.2 可达性分析 标记法

从GC Root 出发,寻找被引用对象

8.5 并发GC

  1. 并发垃圾回收的关键在于标记安全
  2. 混合屏障机制兼顾了安全与效率

8.6 GC 优化

  1. GC主要由系统定时触发或者申请内存触发
  2. GC优化原则是减少在堆上产生垃圾
  3. 使用GC分析工具可以帮助分析GC问题

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值