golang GC 学习

本文深入探讨了Golang的垃圾回收(GC)过程,包括GC执行的STW(Stop the World)、"mark 1"和"mark 2"子阶段、标记终止、清除阶段以及并发清除等步骤。详细阐述了在不同阶段GC如何处理对象、启用写屏障、管理工作队列,并解释了GC率和如何避免长时间暂停以改善并行性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、GC performs sweep termination.(GC执行扫描终止
    a. Stop the world. This causes all Ps to reach a GC safe-point(STW。这将导致所有的P达到GC安全点).
    b. Sweep any unswept spans(清除任何未被清除的span).There will only be unswept spans if this GC cycle was forced before the expected time(如果在预期时间之前强制执行此GC循环,则只会出现未清除的span).

2. GC performs the "mark 1" sub-phase.In this sub-phase, Ps are allowed to locally cache parts of the work queue(GC执行“mark 1”子阶段。在该子阶段,允许Ps本地缓存部分工作队列).
a. Prepare for the mark phase by setting gcphase to _GCmark(from _GCoff), enabling the write barrier, enabling mutator assists, and enqueueing root mark jobs(将gcphase从_GCoff设置为_GCmark,启用写屏障,启用mutator辅助,跟标记任务入队列为mark阶段做准备). No objects may be scanned until all Ps have enabled the write barrier, which is accomplished using stop the world(通过STW,保证在所有的P启用写屏障前没有对象会被扫描到).
b. Start the world. From this point, GC work is done by mark workers started by the scheduler and by assists performed as part of allocation(从这一时刻开始,GC工作由调度程序启动的标记工作程序和作为分配的一部分执行的辅助程序完成). The write barrier shades both the overwritten pointer and the new pointer value for any pointer writes (see mbarrier.go for details)(写屏障回味任何指针写操作着色对覆盖的指针和新指针值(参见mbarrier.go,获取详细信息)). Newly allocated objects are immediately marked black(所有新分配的对象会被马上标记为黑色).
c. GC performs root marking jobs(GC执行跟标记任务). This includes scanning all stacks, shading all globals, and shading any heap pointers in off-heap runtime data structures(这包括扫描所有堆栈,着色所有全局变量,以及着色off-heap运行时数据结构中的任何堆指针). Scanning a stack stops a goroutine, shades any pointers found on its stack, and then
resumes the goroutine(扫描一个栈会停止一个goroutine,将这个栈上发现的所有指针着色,然后恢复这个goroutine).
d. GC drains the work queue of grey objects, scanning each grey object to black and shading all pointers found in the object (which in turn may add those pointers to the work queue)(GC会清空标记为灰色的工作队列,扫描所有灰色的对象,将其引用的对象标记为灰色并将改对象着色为黑色,反过来可能会将这些指针添加到工作队列中).

3. Once the global work queue is empty (but local work queue caches may still contain work), GC performs the "mark 2" sub-phase(一旦全局工作队列为空(但本地工作队列高速缓存可能仍包含工作),GC将执行“mark 2”子阶段).
a. GC stops all workers, disables local work queue caches, flushes each P's local work queue cache to the global work queue cache, and reenables workers(GC停止所有工作任务,禁用本地工作队列缓存,将每个P的本地工作队列缓存刷新到全局工作队列缓存,并重新启用工作任务).
b. GC again drains the work queue, as in 2d above(GC再次清空工作队列,像上面2d描述一样).

4. Once the work queue is empty, GC performs mark termination(一旦工作队列为空,GC将执行标记终止).
a. Stop the world.
b. Set gcphase to _GCmarktermination, and disable workers and  assists(将gcphase设置为_GCmarktermination,并禁用所有工作和辅助回收).
c. Drain any remaining work from the work queue (typically the  will be none)(从工作队列中删除任何剩余的工作,通常为空).
d. Perform other housekeeping like flushing mcaches(执行其他内务管理,如刷新mcaches).

5. GC performs the sweep phase(GC执行清除阶段).
   a. Prepare for the sweep phase by setting gcphase to _GCoff, setting up sweep state and disabling the write barrier(将gcphase设置为_GCmarktermination,设置清除状态并禁用写屏障).
   b. Start the world. From this point on, newly allocated objects are white, and allocating sweeps spans before use if necessary(start the world,从这一刻开始,所有新分配的对象被标记为白色,如果需要,在使用前分配清除的span).
   c. GC does concurrent sweeping in the background and in response  to allocation(GC在后台并发执行清除工作,并为分配空间相应). See description below(见下面的描述).

6. When sufficient allocation has taken place, replay the sequence starting with 1 above(当分配的空间足够时,从上面1开始按顺序重新执行). See discussion of GC rate below(请参阅以下有关GC率的讨论).

Concurrent sweep(并发清除).
The sweep phase proceeds concurrently with normal program execution(清除阶段与正常的程序执行同时进行).
The heap is swept span-by-span both lazily (when a goroutine needs another span) and concurrently in a background goroutine (this helps programs that are not CPU bound)(堆是逐个span清除,包括当goroutine需要新的span是懒操作和在一个后台goroutine中并发操作,这有助于不受CPU限制的程序).
At the end of STW mark termination all spans are marked as "needs sweeping"(在STW标记终止的后,所有的span都标记为“需要清除”。).

The background sweeper goroutine simply sweeps spans one-by-one(后台清除goroutine一个span接一个span的简单清除).

To avoid requesting more OS memory while there are unswept spans, when a goroutine needs another span, it first attempts to reclaim that much memory by sweeping(为了避免在存在未扫描的span时请求更多的OS内存,当goroutine需要另一个span时,它首先尝试通过清除来回收这些内存). When a goroutine needs to allocate a new small-object span, it sweeps small-object spans for the same object size until it frees at least one object(当一个goroutine需要分配一个新的小对象span时,它会扫描相同大小的小对象span,直到释放至少一个对象为止). When a goroutine needs to allocate large-object span from heap, it sweeps spans until it frees at least that many pages into heap(当goroutine需要从堆中分配大对象span时,它会扫描span直到它将至少多page释放到堆中). There is one case where this may not suffice: if a goroutine sweeps and frees two nonadjacent one-page spans to the heap, it will allocate a new two-page span, but there can still be other one-page unswept spans which could be combined into a two-page span(有一种情况,这可能是不能满足的:如果goroutine扫描并释放两个不相邻的单页跨度到堆,它将分配一个新的两页span,但仍然可以有其他单页未扫描span可能是合并为两页跨度).

It's critical to ensure that no operations proceed on unswept spans (that would corrupt mark bits in GC bitmap)(确保未清除的span没有操作行为(这会破坏GCbitmap中的标记位)是至关重要的). During GC all mcaches are flushed into the central cache, so they are empty(在GC期间,所有mcache都被刷新到central cache,因此它们是空的). When a goroutine grabs a new span into mcache, it sweeps it(当一个goroutine抓取一个新的span到mcache时会清除它).When a goroutine explicitly frees an object or sets a finalizer, it ensures that the span is swept (either by sweeping it, or by waiting for the concurrent sweep to finish)(当goroutine显式释放对象或设置终结器时,它确保对span是被清除的(通过直接清除或等待并发清除完成)).The finalizer goroutine is kicked off only when all spans are swept(终结器goroutine只有在清除过所有span后才会启动).When the next GC starts, it sweeps all not-yet-swept spans (if any)(当下一次GC开始时,它将清除所有尚未扫描的span(如果有的话)).

GC rate(GC率).
Next GC is after we've allocated an extra amount of memory proportional to the amount already in use(下一次GC是在我们分配了与已经使用的内存成比例的额外内存量之后). The proportion is controlled by GOGC environment variable (100 by default)(比例由GOGC环境变量控制(默认为100)). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M (this mark is tracked in next_gc variable)(如果GOGC=100,我们使用的是4M,那么当达到8M时,我们将再次进行GC(这个标记在next_gc变量中被跟踪)). This keeps the GC cost in linear proportion to the allocation cost. Adjusting GOGC just changes the linear constant (and also the amount of extra memory used)(这使得GC成本与分配成本成线性增长。调整GOGC只会改变线性常数(以及额外使用的内存数量)).

Oblets()
In order to prevent long pauses while scanning large objects and to improve parallelism, the garbage collector breaks up scan jobs for objects larger than maxObletBytes into "oblets" of at most maxObletBytes(为了防止在扫描大型对象时出现长时间的暂停,并提高并行性,垃圾收集器将大于maxObletBytes的对象的扫描作业分解为至多包含maxObletBytes的“oblet”). When scanning encounters the beginning of a large object, it scans only the first oblet and enqueue the remaining  oblets as new scan jobs(当扫描遇到一个大对象的开头时,它只扫描第一个oblet,并将其余oblet作为新的扫描作业排队).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值