Go语言内存管理详解1|青训营笔记

70 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 7 天
主题:Go语言内存管理

自动内存管理

1.自动内存管理

动态内存:程序在运行时根据需求动态分配的内存 malloc()。
自动内存管理(垃圾回收):由程序语言的运行时系统回收动态内存。避免手动内存管理,专注于实现业务逻辑,保证内存使用的正确性和安全性:double-free problem,use-after-free problem
任务:为新对象分配空间,找到存活对象,回收死亡对象的内存空间。
一些相关概念:
mutator:业务线程,分配新对象,修改对象指向关系。
Collector:GC线程,找到存活对象,回收死亡对象的内存空间。
Serial GC:只有一个Collector。
Parallel GC:支持多个collectors同时回收的GC算法。
Concurrent GC:mutator(s)和collector(s)可以同时执行。
collectors必须感知对象指向关系的改变。

2.追踪垃圾回收

对象被回收的条件:指针指向关系不可达的对象,根据对象的生命周期,使用不同的标记和清理策略。
标记根对象,静态变量、全局变量、常量、线程栈等。
标记找到可达对象,求指针关系的闭包,从根对象出发,找到所有可达对象。
清理所有不可达对象,将存活对象复制到另外的内存空间(Copying GC),将死亡对象的内存标记为“可分配”(Mark-sweep GC),移动并整理存活对象(Mark-compact GC)。

3.分代GC(Generational GC)

分代假说(Generation hypothesis):most objects die young.
Intuition:很多对象在分配出来后很快就不再使用了。
每个对象都有年龄:经过GC的次数。
目的:对年轻和老年的对象,制定不同的GC策略,降低整体内存管理的开销。不同年龄的对象处于heep的不同区域。
年轻代(young generation)
常规的对象分配。存活对象少可以采用copying collection。GC吞吐率很高。
老年代(Old generation) 对象趋向于一直活着,反复复制开销较大,可以采用mark-sweep collection

4.引用计数

每个对象都有一个与之相关联的引用数目。对象成活条件是当且仅当引用数大于0。
优点:
内存管理的操作被平摊到程序执行过程中。
内存管理不需要了解runtime的实现细节,即C++智能指针(smart pointer)。
缺点:
维护引用计数的开销较大,通过原子操作保证对引用计数操作的原子性和可见性。
无法回收环形数据结构——weak reference。
内存开销上,每个对象都引入的额外内存空间存储引用数目。
回收内存时可能引发暂停。