Go语言的内存管理和垃圾回收(GC)
Go语言使用三色标记法回收内存
Go语言的GC是自动管理内存的机制,垃圾回收器会尝试回收程序不再使用的对象和占用的内存
常见垃圾回收算法:
- 1.引用计数
- 2.标记-清除 Go
- 3.分代收集
引用计数:
对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0时回收该对象
优点:对象可以很快被回收
缺点:不能很好的处理循环引用,而且实时的维护引用计数也有一定的代价
代表语言:php,python
标记-清除:
从根变量开始遍历所有引用的对象,引用的对象标记为”被引用”,没有被标记的变量被回收
优点:解决引用计数的缺点,不能很好的处理循环引用,而且实时的维护引用计数也有一定的代价的缺点
缺点:暂停程序的执行
代表语言:Go (三色标记法)
分代收集
按照对象生命周期的长短划分不同的代空间,生命周期长的放入老年代,而短的放入新生代,不同代有不同的回收算法和回收频率
优点:收回性能好
缺点:算法复杂
代表语言:java
Go的垃圾回收
Go垃圾回收的原理是,标记出哪些内存还在使用中,(即被引用到),哪些内存不在使用了(即未被引用),把未被引用的内存回收,以供后续内存分配时再使用
缺点就是,不是实时的回收内存,而是暂停程序的执行去处理内存回收
三色标记法
这里的三色是对应了垃圾回收过程中对象的三种状态
1.灰色:对象还在标记队列中等待
2.黑色:对象已经被标记(该对象不会在本次GC中被清理)
3.白色:对象未被标记(该对象会在本次GC中被清理)
Go的STW
Go中的STW(Stop The World)就是停止所有的goroutine,专心做垃圾回收,待垃圾回收结束后,再恢复goroutine,STW的长短直接影响了程序的性能
垃圾回收优化
1.写屏障
就是让goroutine与GC同时运行的手段,GC过程中新分配的内存会被立即标记,即本轮不回收,下次GC时再确定
2.补助GC
使用goroutine参与一部分的GC工作来提高性能
垃圾回收的触发时机
1.内存分配量达到阈值触发GC
每次内存分配时都会检查当前内存分配量是否已达到阈值,如果达到阈值则立即触发GC
阈值 = 上次GC内存分配量 X 内存增长率
内存增长率由环境变量GOGC控制,默认为100,即每当内存扩大一倍时启动GC
2.定期触发GC
默认情况下,最长两分钟触发一次GC
3.手动触发
使用 runtime.GC() 来手动触发GC
主要用于GC的性能测试和统计
逃逸分析
是指由编译器决定内存分配的位置,不需要程序员指定
在函数中申请一个新的对象:
如果分配在栈中,则函数执行结束后,可自动将内存回收
如果分配在堆中,则函数执行结束后可交给GC(垃圾回收)处理
1.逃逸策略
在函数中申请新的对象时,编辑器会根据该对象是否被函数外部引用来决定是否逃逸:
如果函数外部没有引用,则优先放在栈中
如果函数外部存在引用,则必定存放在堆中
注意:对于仅在函数内部使用的变量,也有可能存放在堆中,比如内存过大,超过栈的存储能力
使用interface类型存在逃逸的可能(动态类型逃逸)
闭包引用对象逃逸