王柳 发表于 2024-1-24 03:25:22

go gc

垃圾回收 (Garbage Collecting)思路

1. "标记-清除〞go的做法

2. "标记-整理〞标记后删除, 删除后重新把内存空间整理java 早期

3. "标记 - 复制〞两块相似的内存, 直接把有用的拷贝到另外一块上去java 现阶段Go因为堆内存结构的独特优势,选择最简单的标记-清除
找到有引用的对象,剩下的就是没有引用的
如何标记

有用的对象从哪里开始找

1. 被栈上的指针引用 一块堆上对象, 现在被栈上指针引用了, 栈上是正则运行的程序 .

2. 被全局变量指针引用

3. 被寄存器中的指针引用 当做参数或者中间变量,放入了寄存器中,也是正则运行的

上述变量被称为 Root Set (GC Root)https://img2023.cnblogs.com/blog/595074/202312/595074-20231203225104506-1341195190.png搜索算法 有广度优先和深度优先
广度优先遍历,指的是从图的一个未遍历的节点出发,先遍历这个节点的相邻节点,再依次遍历
每个相邻节点的相邻节点。

深度优先从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回
退到上一个节点,再从另一条路开始走到底...,不断递归重复此过程,直到所有的顶点都遍历完成.三色标记法

1. 所有的堆对象都是白色的.   
2.Root set 置为灰色   // 要开始分析 这些对象引用了 上面白色的那些对象
3. 置为黑色// 经过分析, 被root 对象直接 或者间接引用了
4. 最终只会存在 白色 和 黑色两种, 最后一层灰色对象没有引用其他对象,置为黑色
5. 清理白色对象.串行GC标记 STW

Stop The World, 暂停所有其他协程
通过可达性分析,找到无用的堆内存
释放堆内存
恢复所有其他协程问题: 暂停了所有协程, 性能不好
并发标记 删除

归纳下: 当标记开始时, 如果有对象被别的对象删除了, 不引用了, 但是 又被前面已经分析过的对象引用, 就会造成, 误清理.

解决办法: gc开始后,被删除的对象,置为灰色. 就意味着不光删除对象不会被清理, 而且删除对象引用的对象也不会被清理. 如果确实没有被引用了, 下次gc时候,肯定会被删除.下面图, 表达就是描述的信息:
https://img2023.cnblogs.com/blog/595074/202312/595074-20231203231315443-1417066516.pnghttps://img2023.cnblogs.com/blog/595074/202312/595074-20231203231524354-1701222497.pnghttps://img2023.cnblogs.com/blog/595074/202312/595074-20231203231606679-1747105824.pnghttps://img2023.cnblogs.com/blog/595074/202312/595074-20231203231657495-1015239327.png删除屏障

并发标记时, 对指针释放的白色对象置灰https://img2023.cnblogs.com/blog/595074/202312/595074-20231203231805441-1369576335.png删除屏障可以杜绝在GC标记中被释放的指针,被清理, 真没被引用了,下次GC会被删除
并发标记 删除

类似上面的 插入 ,基本一个套路.
https://img2023.cnblogs.com/blog/595074/202312/595074-20231203232254070-1911755191.pnghttps://img2023.cnblogs.com/blog/595074/202312/595074-20231203232351139-373070620.pnghttps://img2023.cnblogs.com/blog/595074/202312/595074-20231203232454150-63361819.png插入屏障

并发标记时, 对指针新指向的白色对象置为灰https://img2023.cnblogs.com/blog/595074/202312/595074-20231203232602905-245513766.png混合屏障

包含删除和插入.

被删除的堆对象标记为灰色
被添加的堆对象标记为灰色GC的触发

1. 系统定时触发

sysmon定时检查

如果2分钟内没有过GC,触发

   p0协程一直在检查GC, 发现2分钟没有触发,就会主动触发.在runtime的 proc.go 中有定义:
    // forcegcperiod is the maximum time in nanoseconds between garbage
    // collections. If we go this long without a garbage collection, one
    // is forced to run.
    var forcegcperiod int64 = 2 * 60 * 1e92. 用户显式触发

用户调用runtime.GC方法
并不推荐调用3. 申请内存时触发

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

在mallocgc 中有体现. 有兴趣的可以去看下源码.GC优化原则

1. 尽量少在堆上产生垃圾

2. 内存池化

类似channel的缓存空间

3. 减少逃逸
   
    逃逸会使原本在栈上的对象进入堆中, 例如fmt包返回指针

4. 使用空结构体GC分析工貝

go tool pprof

go tool trace

go build -gcflags= "m"

GODEBUG =" gctrace=1"这个最直接GODEBUG使用

https://img2023.cnblogs.com/blog/595074/202312/595074-20231203234518356-294557834.png
[*]run main.go
https://img2023.cnblogs.com/blog/595074/202312/595074-20231203234642250-1409328644.png这里主要关注 %比, 例如 5%代表 系统有5%的时间,在做GC. gc在标记阶段是并行的, 但是在一些关键节点,还是不能并行.
这个值如果超过 10%就要排查下问题和优化了.

4 ->6->5MGC开始时候 4M 过程中 6M 结束时候 5M

p 是线程的个数
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: go gc