0%

Go Lang GC 学习笔记

GC的具体实现一直在改变,但是其模型是相对稳定的。

collection的三个阶段:

  • Mark Setup - STW
  • Marking - Concurrent
  • Mark Termination - STW

Mark Setup:当进行gc时,为了保证数据完整性,需要设置Write Barrier,这要求将所有的goroutine停止,正常情况下这个时间平均为10-30ms。但是当goroutine停止不下时,会让这个时间变长。调度器目前停止goroutine的时机是在goroutine执行函数调用的时候,因为这样做才能保证安全。假如某个goroutine一直在执行循环,而不执行函数调用,它就无法被停止,这不仅会耽误gc第一个阶段的完成,还会造成其他goroutine停止着。将在Go1.14引入 preemptive techniques 尝试对此进行优化。

Marking - Concurrent:当设置好Write Barrier后,collector会拿走25%可用的CPU,用于mark操作。mark操作,会遍历所有goroutine的栈,寻找指针指向的heap内存,将仍在使用的内存标记一下。这个时候,goroutine是可以并发执行的。在mark的过程,其他正在运行的goroutine可以分配内存,这可能导致内存不够用,这时候需要Mark Assits。Mark Assits,是指短暂停止正在运行的goroutine,让它们来帮忙mark,加快mark的进度。当然,这会影响这些goroutine的执行,collector的目标是尽可能减少Mark Assits的需要。

Mark Termination - STW:Mark完成后,需要关闭Write Barrier,进行多项清理工作,设定下次collection的目标。在进行这些工作前,仍要求所有的goroutine停止。这些工作平均持续60~90ms。虽然也可以设计成边Termination边正常运行一些gorutine的模式,但是设计者认为这样得到的收益很小,而增加的复杂性较高,所以选择了这种STW的实现方式。当Termination工作完成后,回到正常状态。

在collection完成后,会进行sweeping。

sweep是指将那些没有标记为使用的heap内存回收,它不是发生在一次collection中,而是被均摊到每次分配内存的时候。

以上所有行为只有在GC开始且正在进行的时候发生,GC Percentage对collection有很大影响。GC Pencentage,默认是100%。将GC Pencentage设置为100%,意味着下次GC会在heap达到当前GC的mark live内存的2倍时进行。

GC trace可用于追踪collection。GODEBUG=gctrace=1 ./app可查看GC信息,输出到stderr

GC trace:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 通过设置环境变量查看GC trace
GODEBUG=gctrace=1 ./app

gc 1405 @6.068s 11%: 0.058+1.2+0.083 ms clock, 0.70+2.5/1.5/0+0.99 ms cpu, 7->11->6 MB, 10 MB goal, 12 P

gc 1406 @6.070s 11%: 0.051+1.8+0.076 ms clock, 0.61+2.0/2.5/0+0.91 ms cpu, 8->11->6 MB, 13 MB goal, 12 P

gc 1407 @6.073s 11%: 0.052+1.8+0.20 ms clock, 0.62+1.5/2.2/0+2.4 ms cpu, 8->14->8 MB, 13 MB goal, 12 P

# GC trace含义
gc 1405 @6.068s 11%: 0.058+1.2+0.083 ms clock, 0.70+2.5/1.5/0+0.99 ms cpu, 7->11->6 MB, 10 MB goal, 12 P

// General
gc 1404 : The 1404 GC run since the program started
@6.068s : Six seconds since the program started
11% : Eleven percent of the available CPU so far has been spent in GC

// Wall-Clock
0.058ms : STW : Mark Start - Write Barrier on
1.2ms : Concurrent : Marking
0.083ms : STW : Mark Termination - Write Barrier off and clean up

// CPU Time
0.70ms : STW : Mark Start
2.5ms : Concurrent : Mark - Assist Time (GC performed in line with allocation)
1.5ms : Concurrent : Mark - Background GC time
0ms : Concurrent : Mark - Idle GC time
0.99ms : STW : Mark Term

// Memory
7MB : Heap memory in-use before the Marking started
11MB : Heap memory in-use after the Marking finished
6MB : Heap memory marked as live after the Marking finished
10MB : Collection goal for heap memory in-use after Marking finished

// Threads
12P : Number of logical processors or threads used to run Goroutines

(全文完)