从源码看Golang的垃圾回收机制, 基于Golang 1.15.3版本。

源码位置

..\Go\src\runtime\mgc.go

源码开头注释部分

Copyright 2009 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
【一些版权相关的解释】

Garbage collector (GC).
【垃圾回收】

The GC runs concurrently with mutator threads, is type accurate (aka precise), allows multiple
GC thread to run in parallel. It is a concurrent mark and sweep that uses a write barrier. It is
non-generational and non-compacting. Allocation is done using size segregated per P allocation
areas to minimize fragmentation while eliminating locks in the common case.
【GC与mutator线程同时运行,类型准确(也称为精确),允许多个GC线程并行运行。 它是使用写入屏障的**并发标记和清除CMS**。 它是非代际和紧凑的。 使用每个P分配区域隔离的大小来完成分配,以最大程度地减少碎片,同时消除常见情况下的锁定。】

The algorithm decomposes into several steps.
This is a high level description of the algorithm being used. For an overview of GC a good
place to start is Richard Jones' gchandbook.org.

The algorithm's intellectual heritage includes Dijkstra's on-the-fly algorithm, see
Edsger W. Dijkstra, Leslie Lamport, A. J. Martin, C. S. Scholten, and E. F. M. Steffens. 1978.
On-the-fly garbage collection: an exercise in cooperation. Commun. ACM 21, 11 (November 1978),
966-975.
For journal quality proofs that these steps are complete, correct, and terminate see
Hudson, R., and Moss, J.E.B. Copying Garbage Collection without stopping the world.
Concurrency and Computation: Practice and Experience 15(3-5), 2003.

1. GC performs sweep termination.

   a. Stop the world. This causes all Ps to reach a GC safe-point.

   b. Sweep any unswept spans. There will only be unswept spans if
   this GC cycle was forced before the expected time.

2. GC performs the mark phase.

   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. No objects may be
   scanned until all Ps have enabled the write barrier, which is
   accomplished using STW.

   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. The write barrier shades both the
   overwritten pointer and the new pointer value for any pointer
   writes (see mbarrier.go for details). Newly allocated objects
   are immediately marked black.

   c. GC performs root marking jobs. This includes scanning all
   stacks, shading all globals, and shading any heap pointers in
   off-heap runtime data structures. Scanning a stack stops a
   goroutine, shades any pointers found on its stack, and then
   resumes the 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).

   e. Because GC work is spread across local caches, GC uses a
   distributed termination algorithm to detect when there are no
   more root marking jobs or grey objects (see gcMarkDone). At this
   point, GC transitions to mark termination.

3. GC performs mark termination.

   a. Stop the world.

   b. Set gcphase to _GCmarktermination, and disable workers and
   assists.

   c. Perform housekeeping like flushing mcaches.

4. GC performs the sweep phase.

   a. Prepare for the sweep phase by setting gcphase to _GCoff,
   setting up sweep state and disabling the write barrier.

   b. Start the world. From this point on, newly allocated objects
   are white, and allocating sweeps spans before use if necessary.

   c. GC does concurrent sweeping in the background and in response
   to allocation. See description below.

5. When sufficient allocation has taken place, replay the sequence
starting with 1 above. See discussion of GC rate below.

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).
At the end of STW mark termination all spans are marked as "needs sweeping".

The background sweeper goroutine simply sweeps spans one-by-one.

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. 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. When a goroutine needs to allocate large-object span from heap,
it sweeps spans until it frees at least that many pages into heap. 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.

It's critical to ensure that no operations proceed on unswept spans (that would corrupt
mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
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).
The finalizer goroutine is kicked off only when all spans are swept.
When the next GC starts, it sweeps all not-yet-swept spans (if any).

GC rate.
Next GC is after we've allocated an extra amount of memory proportional to
the amount already in use. The proportion is controlled by GOGC environment variable
(100 by default). 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). 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).

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. When scanning encounters the beginning of a large
object, it scans only the first oblet and enqueues the remaining
oblets as new scan jobs.

源码注释部分解释

Go完整的的GC过程主要包括四个部分。

参考


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

RANSAC 算法介绍 下一篇