这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
Go 语言内存管理
自动内存管理
动态内存:程序在运行时根据需求动态分配内存,也就是malloc,其他语言也是有的。
垃圾回收(GC):语言的运行时系统管理动态内存
为什么要有垃圾回收机制呢:分配在堆上的内存不会再使用时,Go语言将会自动回收分配在堆上的内存,从而避免系统的内存被占满。Go的自动回收内存的特性,使得Go程序开发者可以更加专注于代码的效率,很大程度上避免了内存的泄漏。
垃圾回收(GC)
Go语言的老版本采用的是串行GC。首先根据可达性分析法,采用广度优先搜索算法,先从根集合出发寻找被应用的对象,对内存标记。串行GC的缺点:需要暂停所有的业务,对性能的影响较大,难以支持高并发。
而现在的版本是并发 GC,使用的是三色标记,三色标记法。
黑色:表示有用的对象,并且已经分析扫描完 灰色:有用,但是未分析扫描完 白色:暂时无用
首先一开始所有的对象都是白色的,从根节点出发,将根节点可达的对象置为灰色。然后将灰色节点指向的节点置为灰色节点,分析完一个灰色节点的所有指向后将灰色该灰色节点置为黑色,表示该节点有用,并且已经扫描完。然后重复上一步直到没有节点的颜色发生变化,剩下的白色节点就是无用的节点。
分代GC
分代 GC 是垃圾回收的另一个策略,简单来说就是把生命周期短的分为一类,生命周期长的分为一类,然后用不同的策略去管理,降低整体的开销,是一个非常不错的方法。
内存管理
Go的内存分配是提前将内存分块,然后再从这一块不断分小块,Go 内存管理构成了多级缓存机制,从 OS 分配得的内存被内存管理回收后,也不会立刻归还给 OS,而是在 Go runtime 内部先缓存起来,从而避免频繁向 OS 申请内存。mspan, mcache 和 mcentral 构成了内存管理的多级缓存机制。
但是如果这样,对象分配是非常高频的操作,占用很多 CPU,这个时候字节有一个不错的优化方案:通过绑定一大块内存(1kb),然后用于小对象分配(小于128B),使用Bump pointer风格对象分配,可以很大的提高效率。
Bump pointer
Bump-the-pointer(撞点)跟踪在空间创建的最后一个对象,这个对象会被放在空间的顶部。如果之后需要创建对象,只需检查空间是否有足够的剩余空间。如果有,对象就会被创建在里面并且被放置在顶部(此时会更换标记位)。这样一来,每次创建新的对象时,只需要检查最后被创建的对象。这将极大地加快内存分配速度。