本文继续了解runtime库的功能函数。
1 系统调用包装 runtime internal syscall
这是一个推送链接名,将Syscall6导出为
syscall.RawSyscall6。
go:uintptrkeepalive,因为uintptr参数可能是转换后的指针。
因为uintptr参数可能是转换后的指针,需要在调用者中保持活力(这对Syscall6是隐含的,因为它没有主体)。
go:nosplit 因为堆栈复制没有考虑uintptrkeepalive,所以堆栈必须不增长。堆栈复制不能盲目地假设所有uintptr 参数都是指针,因为有些值可能看起来像指针。
但并不是真正的指针,而调整它们的值会破坏调用。
这是一个独立的包装器,因为我们不能把一个函数导出为两个名称。汇编实现自己的名字Syscall6将不会被受到链接名的影响。
2 运行时执行跟踪 runtime trace
trace包含了为程序生成痕迹的设施为执行跟踪器生成跟踪。
- 追踪运行时的活动
执行跟踪可以捕捉到各种各样的执行事件,如 goroutine创建/阻塞/解阻塞,系统调用进入/退出/阻塞。
与GC有关的事件、堆大小的变化、处理器的启动/停止等。 当CPU分析被激活时,执行追踪器会努力将这些样本也包括在内。
也包括这些样本。 当CPU剖析激活时,执行跟踪器也会努力包括这些样本。
大多数事件都会被捕获。生成的跟踪可以被解释为 使用 go tool trace 。
go test 支持跟踪用标准测试包构建的测试和基准。
go test 中内置了对测试和基准的跟踪。
例如,下面的 命令在当前目录下运行测试,并写入跟踪 文件(trace.out)。
go test -trace=trace.out
这个运行时/跟踪包提供了一些API,以便在一个独立的程序中添加等效的跟踪功能。
还有一个标准的HTTP接口来追踪数据。添加以下一行将在/debug/pprof/trace URL下安装一个处理程序来下载一个实时跟踪。
import _ "net/http/pprof"
请参阅 net/http/pprof 软件包,以了解更多关于这个导入的所有调试端点的详细信息。
用户标注包trace提供了用户注解API,可以用来 在执行过程中记录有趣的事件。
有三种类型的用户注解:日志信息、区域。 和任务。
日志会向执行跟踪系统发送一条有时间戳的消息,同时还有 额外的信息,如消息的类别和 哪个goroutine调用了Log。
执行追踪器提供的用户界面可以利用日志类别和消息来过滤 和分组goroutine,使用Log的类别和提供的消息。
在日志中的一个区域是用来记录一个goroutine执行过程中的时间间隔的。
根据定义,一个区域在同一个goroutine中开始和结束。
区域可以被嵌套以表示子间隔。
例如,下面的代码记录了执行中的四个区域 追踪卡布奇诺制作过程中连续步骤的持续时间操作。
trace.WithRegion(ctx, "makeCappuccino", func() {
orderID allows to identify a specific order
among many cappuccino order region records.
trace.Log(ctx, "orderID", orderID)
trace.WithRegion(ctx, "steamMilk", steamMilk)
trace.WithRegion(ctx, "extractCoffee", extractCoffee)
trace.WithRegion(ctx, "mixMilkCoffee", mixMilkCoffee)
})
任务是一个更高层次的组件,它有助于追踪逻辑上的诸如RPC请求、HTTP请求或一个可能需要多个goroutines的有趣的本地操作。
可能需要多个Goroutines一起工作的有趣的本地操作一起工作。
由于任务可能涉及多个goroutines。
它们是通过context.Context对象来追踪的。NewTask创建一个新的任务并将其嵌入返回的context.Context对象中。
如果有的话,日志信息和区域被附加到任务中,在传递给 Log 和 WithRegion 的 Context。
例如,假设我们决定将牛奶打成泡沫,提取咖啡。并在不同的goroutine中混合牛奶和咖啡。通过一个任务。
追踪工具可以确定在一个特定的卡布奇诺的订单。
ctx, task := trace.NewTask(ctx, "makeCappuccino")
trace.Log(ctx, "orderID", orderID)
milk := make(chan bool)
espresso := make(chan bool)
go func() {
trace.WithRegion(ctx, "steamMilk", steamMilk)
milk <- true
}()
go func() {
trace.WithRegion(ctx, "extractCoffee", extractCoffee)
espresso <- true
}()
go func() {
defer task.End() When assemble is done, the order is complete.
<-espresso
<-milk
trace.WithRegion(ctx, "mixMilkCoffee", mixMilkCoffee)
}()
跟踪工具通过测量任务创建和任务结束之间的时间来计算任务的延迟。
任务创建和任务结束之间的时间,并提供追踪中发现的每种任务类型的延迟分布。
3 内存分配器统计信息 runtime ReadMemStats
返回的内存分配器统计信息是在调用ReadMemStats时最新的。
调用ReadMemStats。这是与堆统计不同的。
它是最近完成的垃圾收集周期的一个快照。收集周期的快照。
4 运行时指标 runtime metrics
metrics 提供了一个稳定的接口来访问实现定义的度量的稳定接口。
这个包类似于现有的函数如runtime.ReadMemStats和debug.ReadGCStats,但明显更通用。
这个包所定义的指标集可以随着运行时本身的发展而变化变化,也使得不同的Go实现有不同的变化,其相关的度量集可能不会相交。
- 接口
由一个字符串键指定,而不是例如结构中的字段名。
结构中的字段名。支持的度量的完整列表总是可以在描述中。
每个描述还包括关于指标的有用信息,关于指标的有用信息。
因此,我们鼓励该API的用户对由All返回的片段定义的指标,以保持跨Go版本的兼容性。
当然,在一些情况下,读取特定的度量是非常重要的。
对于这些情况,我们鼓励用户使用构建标签,尽管指标可能会被弃用和删除。
尽管指标可能会被废弃和删除,但用户应该认为这是一个特殊的、罕见的事件,与特定Go实现的巨大变化相吻合。
恰好是在某个特定的Go实现中发生了非常大的变化。
每个指标衡键都有一个 "种类",描述度量衡值的格式。
为了不影响这个包的用户,一个给定的度量值的 "种类 "保证不会改变。
的 "种类 "被保证不会改变。如果它必须改变,那么一个新的度量将被引入用一个新的键和一个新的 "种类"。
- Metric key format
如前所述,指标 Metric key 是字符串。它们的格式简单且定义明确。
旨在使人和机器都能读懂。它被分成两个部分。
用冒号隔开:一个有根的路径和一个单位。选择将单位包含在钥匙的选择是出于兼容性的考虑:如果一个度量衡的单位发生了变化,它的语义很可能也会发生变化。
也发生了变化,所以应该引入一个新的键。关于Metric key 的路径和单位格式的精确定义的更多细节,见描述结构的名称字段的文档。
- 关于浮点数支持的说明
这个包支持其值为浮点表示的度量。为了提高易用性为了提高使用的方便性,本包承诺不产生以下的类的浮点值。NaN,无穷大。
- 支持的指标
下面是支持的指标的完整列表,按字母顺序排列。
/cgo/go-to-c-calls:calls
当前进程从Go到C的调用数。
/cpu/classes/gc/mark/assist:cpu-seconds
估计执行GC任务的goroutines的总CPU时间以协助GC并防止其落后于应用程序。
这个指标是一个高估,并不能直接与系统CPU时间的测量。只能与其他/cpu/classes度量。
/cpu/classes/gc/mark/dedicated:cpu-seconds
在专门用于GC任务的处理器(由GOMAXPROCS定义)上执行GC任务所花费的CPU总时间估计。
处理器(由GOMAXPROCS定义)专门用于这些任务。
这包括因GC而停止的世界所花费的时间。
这个指标是一个高估,并不能直接与系统CPU时间的测量。
只能与其他/cpu/classes度量。
/cpu/classes/gc/mark/idle:cpu-seconds
估计花费在执行GC任务上的总CPU时间闲置的CPU资源,否则Go调度程序无法找到用的时间。
这应该从总的GC CPU时间中减去来衡量强制性的GC CPU时间。
这个指标是高估的,并不能直接与系统CPU时间的测量。
只能与其他/cpu/classes度量。
/cpu/classes/gc/pause:cpu-seconds
被GC暂停的应用程序所花费的CPU总时间估计。
暂停的总CPU时间。即使在暂停期间只有一个线程在运行,这也是计算为GOMAXPROCS乘以暂停延时,
因为没有其他的可以执行。
这是/gc/pause:seconds中样本的精确总和如果每个样本都乘以拍摄时的GOMAXPROCS。
这个指标是一个高估,并不能直接与系统CPU时间的测量。
只能与其他/cpu/classes度量。
/cpu/classes/gc/total:cpu-seconds
估计执行GC任务的总CPU时间。
这个指标是一个高估,并不能直接与系统CPU时间的测量。只能与其他/cpu/classes度量。
/cpu/classes/gc中所有指标的总和。
/cpu/classes/idle:cpu-seconds
估计总的可用CPU时间,不用于执行任何Go或Go运行时的代码。
换句话说,/cpu/classes/total:cpu-seconds的部分中未使用的部分。
这个指标是高估的,并不能直接与系统CPU时间的测量。
只与其他/cpu/classes度量。
/cpu/classes/scavenge/assist:cpu-seconds
估计CPU花费的总时间,将未使用的内存返回到为了应对内存压力而急切地响应底层平台。
这个指标是一个高估,并不能直接与系统CPU时间的测量。
只能与其他/cpu/classes度量。
/cpu/classes/scavenge/background:cpu-seconds
估计CPU执行后台任务的总时间以将未使用的内存返回到底层平台。
这个指标是一个高估,并不能直接与系统CPU时间的测量。只能与其他/cpu/classes度量。
/cpu/classes/scavenge/total:cpu-seconds
估计CPU在执行任务时花费的总时间,这些任务将未使用的内存返回给底层平台。
未使用的内存到底层平台。
这个指标是一个高估,并不能直接与系统CPU时间的测量。只能与其他/cpu/classes度量。
/cpu/classes/scavenge中所有指标的总和。
/cpu/classes/total:cpu-seconds
用户围棋代码或围棋运行时间的估计总可用CPU时间,如GOMAXPROCS 所定义的。
换句话说,GOMAXPROCS集成了这个进程执行的该进程执行的壁钟时间。
这个指标是一个高估,并不能直接与系统CPU时间的测量。
只与其他/cpu/classes度量。/cpu/classes中所有度量的总和。
/cpu/classes/user:cpu-seconds
估计运行用户Go代码所花费的总CPU时间。
这可能也包括在go运行时间中花费的少量时间。
这个指标是高估的,并不能直接与系统CPU时间的测量。只能与其他 /cpu/classes度量。
/gc/cycles/automatic:gc-cycles
Go运行时产生的已完成的GC周期的计数。
/gc/cycles/forced:gc-cycles
由应用程序强制完成的GC周期的计数。
/gc/cycles/total:gc-cycles
所有完成的GC周期的计数。
/gc/heap/tiny/allocs:objects,
按近似大小分配的堆分配。
注意,这不包括/gc/heap/tiny/allocs:objects所定义的微小对象。
只有微小的块。
/gc/heap/allocs:bytes
应用程序分配到堆中的内存的累计总和。
/gc/heap/tiny/allocs:objects,
由应用程序触发的堆分配的累积计数。
注意,这不包括/gc/heap/tiny/allocs:objects所定义的微小对象。
只有微小的块。
/gc/heap/tiny/allocs:objects,
已释放的堆分配的分布情况,按近似的大小。
注意,这不包括/gc/heap/tiny/allocs:objects所定义的微小对象。
只有微小的块。
/gc/heap/frees:bytes
被垃圾收集器释放的堆内存的累计总和。
/gc/heap/tiny/allocs:objects,
被垃圾收集器释放了存储空间的堆分配的累积计数。
注意,这不包括/gc/heap/tiny/allocs:objects所定义的微小对象。
只有微小的块。
/gc/heap/goal:bytes
GC周期结束时的堆大小目标。
/gc/heap/objects:objects
占用堆内存的对象的数量,活的或不活的。
/gc/heap/tiny/allocs:objects
挤在一起成块的小型分配的计数。
这些分配是与其他分配分开计算的因为每个单独的分配没有被运行时跟踪。
只有它们的块。每个区块已经被计算在allocs-by-size和frees-by-size。
/gc/limiter/last-enabled:gc-cycle
上次启用GC CPU限制器时的GC周期。
这个指标对于诊断内存不足的根本原因很有用,错误的根本原因,因为当GC的CPU时间过高时,限制器会用内存换取CPU时间。
时间过高时,限制器用内存换取CPU时间。
这种情况在使用SetMemoryLimit时最容易发生。
第一个GC周期是周期1,所以数值为0表示它从未被启用。
/gc/pauses:seconds
与GC相关的个别停顿延迟的分布。
/gc/stack/starting-size:bytes
给新例程分配的堆大小
/memory/classes/heap/free:bytes
完全自由的内存,有资格返回给底层系统,但没有被返回的内存,但还没有被返回到底层系统。
这个指标是运行时对由物理内存支持的自由地址空间的估计。
物理内存支持的自由地址空间。
/memory/classes/heap/objects:bytes
活的对象和死的对象所占用的内存,这些对象还没有被垃圾收集器标记为空。
占用的内存,以及尚未被垃圾收集器标记为空的死对象。
/memory/classes/heap/released:bytes
完全自由的内存,并已返回到底层系统。
这个指标是运行时对仍然映射到进程中的的自由地址空间,它仍然被映射到进程中,但是没有物理内存的支持。
/memory/classes/heap/stacks:bytes
从堆中分配的内存被保留为堆栈空间。空间,无论它目前是否在使用中。
/memory/classes/heap/unused:bytes
为堆对象保留的内存,但目前没有被用来存放堆对象。用来存放堆对象。
/memory/classes/metadata/mcache/free:bytes
保留给运行时缓存结构的内存,但不在使用中。不是在使用中的。
/memory/classes/metadata/mcache/inuse:bytes
目前正在使用的运行时缓存结构所占用的内存。目前正在使用。
/memory/classes/metadata/mspan/free:bytes
保留给运行时mspan结构的内存,但不在使用中。不是在使用中的。
/memory/classes/metadata/mspan/inuse:bytes
被运行时mspan结构占用的内存,这些结构目前正在使用。目前正在使用。
/memory/classes/metadata/other:bytes
为运行时保留的或用于保留运行时元数据的内存。元数据。
/memory/classes/os-stacks:bytes
由底层操作系统分配的堆栈内存。
/memory/classes/other:bytes
执行跟踪缓冲区使用的内存,用于调试运行时的结构调试运行时的结构,最后一个程序和剖析器的特殊性,等等。
/memory/classes/profiling/buckets:bytes
堆栈跟踪哈希图所使用的内存,用于剖析。
/memory/classes/total:bytes
所有由Go运行时映射到当前进程的内存作为读写器。
请注意,这并不包括通过cgo或syscall包调用的代码所映射的内存通过 cgo 或 syscall 包调用的代码映射的内存。
/memory/classes中所有指标的总和。
/sched/gomaxprocs:threads
当前运行时.GOMAXPROCS的设置,或者说可以执行用户级Go代码的操作系统线程数。
可以同时执行用户级 Go 代码的操作系统线程数同时进行。
/sched/goroutines:goroutines
活跃的协程数量。
/sched/latencies:seconds
程式在实际运行前在调度器中停留的时间分布
在实际运行前处于可运行状态的时间分布。
/sync/mutex/wait/total:seconds
goroutines在sync.Mutex或sync.RWMutex上被阻塞的大约累计时间。
sync.Mutex或sync.RWMutex上阻塞的大约时间。这个指标对于识别锁争夺的全局变化。
收集一个Mutex或块使用 runtime/pprof 软件包来收集更详细的争夺数据。
Float64Histogram表示float64值的分布。
Buckets包含直方图桶的边界,按递增顺序排列。 Buckets[0]是最小桶的包容性下界,而 Buckets[len(Buckets)-1]是最大桶的专属上界。
因此,有len(Buckets)-1个计数。此外,len(Buckets) != 1,总是如此。
因为至少需要两个边界来描述一个桶(而0边界用于描述0个桶)。
Buckets[0]被允许有-Inf的值,Buckets[len(Buckets)-1]被允许有Inf值。
对于一个给定的度量名称,Buckets的值保证在调用之间不会改变,直到程序退出。
在两次调用之间,直到程序退出。
这个片断的值允许与其他 Float64Histograms 的 Buckets字段,所以里面的值只能被读取。
如果它们需要被修改,用户必须制作一个副本,Counts包含每个直方图桶的权重。
给定N个桶,Count[n]是范围内的权重
[bucket[n], bucket[n+1]),为0 <= n < N。
Sample Read 采样读取在给定的公制样本片中的每个Value字段。
所期望的度量应该存在于具有适当名称的片断中。
我们鼓励这个API的用户在不同的调用中重复使用同一个片断,以提高效率,但不必须这样做。
注意,重复使用有一些注意事项。值得注意的是,不应该在读取或当一个带有该值的读操作尚未完成时,不应该对该值进行操作;那是一种数据竞争。
这个属性包括指针类型的值(例如,Float64Histogram)。
它们的底层存储将尽可能地被Read重用。为了安全地使用这种值,所有的数据必须被深度复制。
并发执行多个Read调用是安全的,但是它们的参数必须不共享底层内存。
如果有疑问,可以从头开始创建一个新的[]样本。从头开始,这总是安全的,虽然可能效率不高。
如果Sample的名字没有出现在All中,那么它的Value将被填充为KindBad,以表明它是不存在的。
作为KindBad,以表明该名称是未知的。
5 变量注册 runtime msan asan
cgo 相关 和 注册全局变量。
10 覆盖率分析 runtime coverage
- 函数 WriteMetaDir
为当前正在运行的程序写一个覆盖元数据文件到'dir'指定的目录中。
运行的程序写入'dir'中指定的目录。如果该操作不能成功完成,将返回一个错误,如果该操作不能成功完成。
将返回一个错误(例如,如果当前运行的程序没有用"-cover",或者该目录不存在)。
- 函数 emitState
emitState在发射过程中保存有用的状态信息。
当一个被检测的程序完成执行并开始覆盖数据的过程中,有可能在输出目录中已经存在一个现有的元数据文件。
在这种情况下,下面的openOutputFiles()会将下面的'mf'字段保留为零。
如果需要一个新的元数据文件,'mfname'字段将是元文件的最终路径,
'mftmp'将是一个 临时文件,而'mf'将是一个打开的os.File指针,用来指向'mftmp'。
元数据文件的有效载荷将被写入'mf',这个然后关闭临时文件并重新命名(从'mftmp'到mfname'),以确保元数据文件是以原子方式创建的。
我们希望这样做,
以便在以下情况下工作顺利:
以便在一个给定的被测程序有多个实例的情况下顺利进行。
一个给定的工具程序有几个实例,都在同一时间终止,并试图同时创建元数据文件。
对于计数器数据文件来说,发生碰撞的可能性较小,因此openOutputFiles()将计数器数据文件存储在'cfname'中,并然后把*io.File放到'cf'中。
initHooks 仅由编译器调用。
initHook从主包的 "init "例程中被调用。用"-cover "构建的程序中调用。这个函数的目的是
如果'istest'为假,表明我们正在构建一个普通程序。
("go build -cover ..."),在这种情况下,我们会立即尝试写入,写出元数据文件,并将 emitCounterData 注册为一个退出的钩子。
如果'istest'为真(表明该程序是一个Go测试二进制文件),那么我们就暂且将emitMetaData和emitCounterData作为退出钩子。
在正常情况下(例如,常规的 "gotest -cover "运行),testmain.go模板将在测试结束时运行。
最后,写出覆盖率,然后调用markProfileEmitted(),以表明没有更多的工作需要完成。
然而,如果这个调用没有被执行,这就说明了测试二进制文件被用作工具的替代二进制文件。
因此,我们希望在程序终止时运行退出钩子。然后终止。
6 runtime cgo
cgo包含对cgo工具生成的代码的运行时支持的运行支持。 有关使用cgo的细节,请参见cgo命令的文档以了解使用cgo的细节。
7 剖析工具 runtime pprof
以pprof可视化工具期望的格式写入运行时剖析数据。以格式化写入运行时剖析数据,并由 pprof 可视化工具进行处理。
- 解析一个go程序
剖析Go程序的第一步是启用剖析功能。 支持对用标准测试构建的基准进行剖析。
此包内置在go test中。例如,下面的命令 在当前目录下运行基准,并将CPU和 内存配置文件到 cpu.prof 和 mem.prof。
go test -cpuprofile cpu.prof -memprofile mem.prof -bench .
也有一个标准的HTTP接口来获取剖析数据。添加 以下一行将在/debug/pprof/下安装处理程序。
URL下安装处理程序,以下载实时配置文件。
import _ "net/http/pprof"
更多细节请参见 net/http/pprof 包。 然后,配置文件可以用pprof工具进行可视化。
go tool pprof cpu.prof
在pprof命令行中有许多命令可以使用。 常用的命令包括 "top "和 "web",
"top "可以打印出程序热点的摘要。
"web",它可以打开一个交互式的热点及其调用图。
热点和它们的调用图。使用 "help "可以获得关于 所有的pprof命令。
简介是一个堆栈痕迹的集合,显示了导致特定事件的调用序列。 导致一个特定事件的实例,如分配。
软件包可以创建和维护它们自己的配置文件;最常见的用途是跟踪必须明确关闭的资源,如文件。
最常见的用途是跟踪必须明确关闭的资源,如文件 或网络连接。
type Profile struct {
name string
mu sync.Mutex
m map[any][]uintptr
count func() int
write func(io.Writer, int) error
}
一个Profile的方法可以同时从多个goroutine中调用。
每个配置文件都有一个独特的名称。有几个配置文件是预定义的。
goroutine - stack traces of all current goroutines
heap - a sampling of memory allocations of live objects
allocs - a sampling of all past memory allocations
threadcreate - stack traces that led to the creation of new OS threads
block - stack traces that led to blocking on synchronization primitives
mutex - stack traces of holders of contended mutexes
这些预定义的配置文件会自我维护,并在一个明确的 添加或删除方法的调用时发生恐慌。
堆概况报告了最近完成的垃圾收集的统计数据。
垃圾收集;它忽略了最近的分配,以避免使 它忽略了最近的分配,以避免使概况偏离实时数据而偏向垃圾。
如果根本就没有进行过垃圾收集,那么堆概况就会报告 所有已知的分配。
这种例外情况主要在程序运行时有帮助启用垃圾收集的情况下运行,通常是为了调试。
堆配置文件跟踪了所有活的对象在应用程序内存中的分配位置以及自程序启动以来分配的所有对象。
程序启动后分配的所有对象的分配位置。
Pprof的-inuse_space, -inuse_objects, -alloc_space, 和 -alloc_objects
标志选择要显示的对象,默认为 -inuse_space (实时对象。默认为 -inuse_space (活的对象,按尺寸缩放)。
allocs配置文件与heap配置文件相同,但将默认的 pprof显示为-alloc_space,即自程序开始以来分配的字节总数。
程序开始以来分配的字节总数(包括收集的垃圾字节)。
CPU配置文件不是作为一个配置文件提供的。它有一个特殊的API。
StartCPUProfile和StopCPUProfile函数,因为它在剖析过程中会流向 因为它在剖析过程中会把输出流到一个写入器上。
func StartCPUProfile(w io.Writer) error
StartCPU 配置文件启用了当前进程的CPU剖析。 在进行剖析时,剖析结果将被缓冲并写入w中。
如果已经启用了剖析功能,StartCPUProfile将返回一个错误。
在类似于Unix的系统中,StartCPUProfile在默认情况下对以下情况不起作用 用 -buildmode=c-archive 或 -buildmode=c-shared 构建的 Go 代码。
StartCPUProfile依赖于SIGPROF信号,但该信号会 被传递给主程序的 SIGPROF 信号处理程序(如果有的话)。
而不是Go所使用的那个。
为了使其工作,请调用os/signal.Notify 用于 syscall.SIGPROF,但要注意这样做可能会破坏主程序正在进行的剖析工作。
主程序正在进行的剖析。
运行时例程允许一个可变的剖析率。
但在实践中,操作系统不能触发信号但实际上操作系统不能以超过500ms(hz)的速度触发信号,而我们对信号的处理并不便宜(主要是获取堆栈跟踪)。
100 是一个合理的选择:它足够频繁,足以产生有用的数据,又足够稀少,不会使系统陷入困境。
系统,而且是一个很好的整数,使之容易将样本数转换为秒数。与其要求而不是要求每个客户指定频率,我们对其进行硬编码。
8 小结:
go的1.20 cover该工具现在可以收集整个程序的覆盖率概况,而不仅仅是单元测试。 评估代码单测的覆盖,而runtime包也有较多更新,编译器和垃圾收集器的改进减少了内存开销,并将整体 CPU 性能提高了 2%。。
下一节我们使用runtime 和 unsafe 调整和优化程序,查看几个例子。
参考:
1 关于pprof的更多信息,见
https://github.com/google/pprof/blob/master/doc/README.md.
2 BUG(rsc): 配置文件只有在生成它们的内核支持下才是好的。
https://golang.org/issue/13841
3 GC算法的知识遗产包括Dijkstra的on-the-fly算法,见
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. ACM 21, 11 (November 1978),
966-975.
4 关于GC这些步骤是完整、正确和终止的期刊质量证明,见
Hudson, R., and Moss, J.E.B. Copying Garbage Collection without stopping the world.
Concurrency and Computation: Practice and Experience 15(3-5), 2003.