宁德市路桥建设有限公司网站,wordpress 滑 验证,全网推广成功再收费,一个网站要怎么做的吗背景
正好周末时间#xff0c;就打算梳理以下自己对go gc的理解。跳出语言层面来说#xff0c;gc分为两种#xff0c;一种是手动创建#xff0c;手动销毁。另一种就是由自动分配自动销毁#xff0c;前者就是c,c的代表#xff0c;后者就是java#xff0c;go。 而整个流程…背景
正好周末时间就打算梳理以下自己对go gc的理解。跳出语言层面来说gc分为两种一种是手动创建手动销毁。另一种就是由自动分配自动销毁前者就是c,c的代表后者就是javago。 而整个流程来说的话程序运行-内存分配-垃圾回收至于内存分配这个我留到下一篇来讲解梳理以下。 其中内存分配需要依靠内存分配器而垃圾回收需要垃圾回收器垃圾回收器有不同的垃圾回收算法。
垃圾回收算法
引用技术算法。主要是在程序启动后每个对象初始标记为0如果有别的对象引用该对象那么引用技术就1但是存在一个问题就是循环引用的问题。这个和java中的类似。追踪式垃圾回收可达性分析算法初始标记一些root对象根据这些root对象 递归遍历如果可达的话那么就标记为可用否则剩余对象就是可以被清除的对象。 Go 现在用的三色标记法就属于追踪式垃圾回收算法的一种。
根对象
根对象在垃圾回收的术语中又叫做根集合它是垃圾回收器在标记过程时最先检查的对象包括
全局变量程序在编译期就能确定的那些存在于程序整个生命周期的变量。 执行栈每个 goroutine 都包含自己的执行栈这些执行栈上包含栈上的变量及指向分配的堆内存区块的指针。 寄存器寄存器的值可能表示一个指针参与计算的这些指针可能指向某些赋值器分配的堆内存区块。
在GC的标记阶段首先需要标记的就是根对象, 从根对象开始可到达的所有对象都会被认为是存活的。 根对象包含了全局变量, 各个G的栈上的变量等, GC会先扫描根对象然后再扫描根对象可到达的所有对象。
Mark Sweep
STWStop the World: 需要暂停Mutatur来确定所有的引用关系而这部分也就是优化GC的重点因为STW对于系统的吞吐量来说是非常致命的所以有些业务场景下是不可接受的。Mark Sweep 该过程就是先STW然后用root 根对象去标记可达的对象先标记后清除如下图先通过根对象标记到A B C D G然后清除掉E F。
go 1.1 GC流程
Stop the WorldMark通过 Root 和 Root 直接间接访问到的对象 来寻找所有可达的对象并进行标记。Sweep对堆对象迭代已标记的对象置位标记。所有未标记的对象加入freelist 可用于再分配。Start the Wrold
总结先停止程序然后标记 清除然后在程序正常运行。其实缺点非常明显这种对业务影响是非常大的分配内存慢内存碎片高。
go 1.3 gc流程
我们分析一下其实在清除阶段只要不去干扰对象引用关系其实不会对最终清除的对象有影响。所以mark阶段可以STWSweep阶段可以并发执行。所以1.3的流程就是 mark阶段STW并发Sweep。从一定程度上可以减少STW对程序业务的影响。
go 1.5 gc (三色标记法)
1.5版本在标记过程中使用三色标记法。标记和清扫都并发执行的但标记阶段的前后需要 STW 一定时间来做 GC 的准备工作和栈的re-scan。 什么是三色标记 三色标记是对标记清除法的改进标记清除法在整个执行时要求长时间 STWGo 从1.5版本开始改为三色标记法初始将所有内存标记为白色然后将 roots 加入待扫描队列(进入队列即被视为变成灰色)然后使用并发 goroutine 扫描队列中的指针如果指针还引用了其他指针那么被引用的也进入队列被扫描的对象视为黑色。 白色对象潜在的垃圾其内存可能会被垃圾收集器回收。 黑色对象活跃的对象包括不存在任何引用外部指针的对象以及从根对象可达的对象垃圾回收器不会扫描这些对象的子对象。 灰色对象 活跃的对象因为存在指向白色对象的外部指针垃圾收集器会扫描这些对象的子对象。 其实直接看图的话可以非常明显的明白初始为白色然后将root可达的对象标记为灰色如果这个对象被被的对象引用那么标记为黑色到最后如果不可达对象 必定是白色那么可以被清除。
写屏障和删屏障
1.5版本在标记过程中使用三色标记法。回收过程主要有四个阶段其中标记和清扫都并发执行的但标记阶段的前后需要 STW 一定时间来做GC 的准备工作和栈的 re-scan。 使用并发的垃圾回收也就是多个 Mutator 与 Mark 并发执行想要在并发或者增量的标记算法中保证正确性我们需要达成以下两种三色不变性(Tri-color invariant)中的任意一种 强三色不变性黑色对象不会指向白色对象只会指向灰色对象或者黑色对象。 弱三色不变性 黑色对象指向的白色对象必须包含一条从灰色对象经由多个白色对象的可达路径。 总结其实本上强三色和弱三色 主要就是为了保证在系统和标记对象的过程中不会造成对对象引用关系链造成影响。
写屏障 写屏障的目的其实为了保证在系统执行和标记对象并发执行的之后保证系统的正确性。
writePointer(slot, ptr):shade(ptr)*slot ptr写屏障保证在将黑色对象对象引用到白色对象时这个时候不满足强三色规则会将白色对象标记为灰色对象满足强三色规则。如下图中A对象引用到C将C对象标记为灰色然后A可达C所以A C D设置为黑色。 问题虽然写屏障可以保证强三色不变式但是Go中仅针对堆上的对象进行写屏障而栈中对象写屏障是比较耗费性能的所以要么通过栈上写屏障保证或者通过STW来重新扫描保证对象变黑来保证。 删屏障 删除屏障也是拦截写操作的但是是通过保护灰色对象到白色对象的路径不会断来实现的。也就是若三色不变式。
writePointer(slot, ptr):if (isGery(slot) || isWhite(slot))shade(*slot)*slot ptr混合屏障
插入写屏障和删除写屏障的短板
插入写屏障结束时需要STW来重新扫描栈标记栈上引用的白色对象的存活
删除写屏障回收精度低GC开始时STW扫描堆栈来记录初始快照这个过程会保护开始时刻的所有存活对象。
具体操作: 1、GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描无需STW); 2、GC期间任何在栈上创建的新对象均为黑色; 3、被删除的对象标记为灰色; 4、被添加的对象标记为灰色;
总结
1.GC的过程 标记清除但是关键点在于对STW的合理配合下不影响系统的正常运行由此引入写屏障和删屏障操作来保证强三色和弱三色规则但是本上他们存在一定的问题所以使用混合屏障来保证。
引用
https://www.cnblogs.com/ricklz/p/14155443.html