1.GODEBUG命令运行程序,跟踪内存信息
命令GODEBUG='gctrace=1' ./snippet_mem
用于启用Go程序的调试和性能剖析。当你设置 GODEBUG='gctrace=1' 启用 gctrace 时,Go程序将输入与垃圾收集器相干的调试信息。这对于分析程序的内存治理和性能问题十分有用。
输入信息:
gc # @#s #%: #+#+# ms clock, #+#/#/#+# ms cpu, #->#-># MB, # MB goal, # P
含意:
gc # GC次数的编号,每次GC时递增 @#s 间隔程序开始执行时的工夫 #% GC占用的执行工夫百分比 #+...+# GC应用的工夫 #->#-># MB GC开始,完结,以及以后沉闷堆内存的大小,单位M # MB goal 全局堆内存大小 # P 应用processor的数量
2. runtime代码打印内存信息
2.1runtime.MemStats
也能够利用 runtime库里的ReadMemStats()办法, 读取的内存信息会保留在runtime.MemStats
这个构造体中,能够从这个构造体中获取以后的内存信息,
// MemStats 记录无关内存分配器的统计信息。type MemStats struct { // 通用统计信息。 // Alloc 示意调配的堆对象的字节数。 // // 这与HeapAlloc(见下文)雷同。 Alloc uint64 // TotalAlloc 示意为堆对象累积调配的字节数。 // // TotalAlloc 随着堆对象的调配而减少,但 // 与Alloc和HeapAlloc不同,当 // 对象被开释时,它不会缩小。 TotalAlloc uint64 // Sys 示意从操作系统获取的内存总字节数。 // // Sys 是上面的XSys字段的总和。Sys度量 // 用于Go运行时的堆、栈和其余外部数据结构的虚拟地址空间。 // 在任何给定时刻,可能并非所有虚拟地址空间都由物理内存反对, // 只管总体上它已经都是。 Sys uint64 // Lookups 是运行时执行的指针查找次数。 // // 这次要用于调试运行时外部。 Lookups uint64 // Mallocs 是累积的堆对象调配计数。 // 存活对象的数量是Mallocs - Frees。 Mallocs uint64 // Frees 是累积的堆对象开释计数。 Frees uint64 // 堆内存统计信息。 // HeapAlloc 示意调配的堆对象的字节数。 // // “已调配”的堆对象包含所有可达对象, // 以及垃圾收集器尚未开释的不可达对象。 // 具体来说,HeapAlloc随着堆对象的调配而减少, // 随着堆被扫描和不可达对象被开释而缩小。 // 扫描在GC周期之间逐增地进行,因而这两个过程 // 同时进行,因而HeapAlloc偏向于平滑变动 // (与进行-世界垃圾收集器的典型锯齿形相比)。 HeapAlloc uint64 // HeapSys 示意从操作系统获取的堆内存字节数。 // // HeapSys度量堆的虚拟地址空间的数量 // 为堆保留。这包含虚拟地址空间 // 曾经保留但尚未应用,不耗费物理内存, // 但通常很小,以及虚拟地址空间,其中 // 物理内存在变得未应用后曾经返回给了OS // (请参见HeapReleased以获取后者的度量)。 // // HeapSys预计了堆的最大大小。 HeapSys uint64 // HeapIdle 示意闲暇(未应用)span中的字节数。 // // 闲暇span中不蕴含任何对象。这些span能够 // (并且可能曾经)返回给操作系统,或者能够 // 用于堆调配,或者能够从新用于 // 堆外存储器。 // // HeapIdle减去HeapReleased预计了内存量 // 能够返回给操作系统,但因为运行时保留 // 能够增大堆而不须要从OS申请更多内存。 // 如果这个差别显著大于堆大小,这表明最近 // 存活堆大小的短暂峰值。 HeapIdle uint64 // HeapInuse 示意应用中span中的字节数。 // // 应用中span至多蕴含一个对象。这些span // 只能用于大致相同大小的其余对象。 // // HeapInuse减去HeapAlloc预计了内存量 // 已调配给特定大小类,但以后未应用。 // 这是对碎片的下限,但通常能够无效地重用 // 这段内存。 HeapInuse uint64 // HeapReleased 示意返回给操作系统的物理内存字节数。 // // 这计算了从曾经返回给操作系统的闲暇span中的堆内存。 HeapReleased uint64 // HeapObjects 是已调配的堆对象数量。 // // 与HeapAlloc一样,这会随着对象的调配而减少, // 随着堆的扫描和不可达对象的开释而缩小。 HeapObjects uint64 // 栈内存统计信息。 // // 堆栈不被视为堆的一部分,但运行时 // 能够从新应用堆内存的span来进行堆栈内存,反之亦然。 // StackInuse 示意应用中的stack span中的字节数。 // // 应用中的stack span至多蕴含一个stack。这些 // span只能用于雷同大小的其余stack。 // // 不存在StackIdle,因为未应用的stack span // 返回到堆(因而计入HeapIdle)。 StackInuse uint64 // StackSys 示意从操作系统获取的stack内存字节数。 // // StackSys是StackInuse,加上间接从操作系统取得的任何内存 // 用于OS线程堆栈。 // // 在非cgo程序中,此度量规范目前等于StackInuse // (但不应依赖,该值可能在未来更改)。 // // 在cgo程序中,此度量规范包含间接从操作系统调配的OS线程堆栈。 // 目前,这仅在c-shared和c-archive构建模式下占用一堆的内存, // 并且来自OS的其余堆栈(尤其是由C代码调配的)目前不会被测量。 // 请留神,这也可能会在未来更改。 StackSys uint64 // 堆外存储器统计信息。 // // 以下统计信息测量了运行时内部结构 // 这些构造不是从堆内存调配的(通常不是这样, // 因为它们是堆的一部分的实现)。与 // 堆或堆内存不同,调配给这些 // 构造的内存是专门用于这些构造的。 // // 这些次要用于调试运行时内存开销。 // MSpanInuse 示意调配的mspan构造的字节数。 MSpanInuse uint64 // MSpanSys 示意从操作系统获取的mspan构造的内存字节数。 MSpanSys uint64 // MCacheInuse 示意调配的mcache构造的字节数。 MCacheInuse uint64 // MCacheSys 示意从操作系统获取的mcache构造的内存字节数。 MCacheSys uint64 // BuckHashSys 示意散布桶哈希表中的内存字节数。 BuckHashSys uint64 // GCSys 示意垃圾回收元数据中的内存字节数。 GCSys uint64 // OtherSys 示意杂项堆外运行时调配的内存字节数。 OtherSys uint64 // 垃圾收集器统计信息。 // NextGC 是下一个GC周期的指标堆大小。 // // 垃圾回收器的指标是使HeapAlloc ≤ NextGC。 // 在每个GC周期完结时,依据可达数据的数量和 // GOGC的值来计算下一个周期的指标。 NextGC uint64 // LastGC 是上一个垃圾回收实现的工夫,以 // 纳秒为单位自1970年以来的工夫(UNIX纪元)。 LastGC uint64 // PauseTotalNs 示意自程序启动以来GC的 // 进行-世界暂停的累积纳秒数。 // // 在进行-世界暂停期间,所有goroutine都被暂停 // 只有垃圾回收器能够运行。 PauseTotalNs uint64 // PauseNs 是最近GC进行-世界暂停工夫的循环缓冲区 // 以纳秒为单位。 // // 最近的暂停位于PauseNs[(NumGC+255)%256]。 // 通常,PauseNs[N%256]记录了在最 // 近的N%256th GC周期中暂停的工夫。在一个周期中 // 可能有屡次暂停;这是一个循环缓冲区中所有暂停的总和。 PauseNs [256]uint64 // PauseEnd 是最近GC暂停完结工夫的循环缓冲区, // 以纳秒为单位自1970年以来的工夫(UNIX纪元)。 // // 这个缓冲区的填充形式与PauseNs雷同。 // 在一个周期中可能有屡次暂停;这记录了 // 在一个周期中最初一个暂停的完结。 PauseEnd [256]uint64 // NumGC 是已实现的GC周期数。 NumGC uint32 // NumForcedGC 是应用程序调用GC函数强制进行的GC周期数。 NumForcedGC uint32 // GCCPUFraction 是自程序启动以来 // GC应用的可用CPU工夫的分数。 // // GCCPUFraction示意为0到1之间的数字, // 其中0示意GC没有应用该程序的CPU。程序的 // 可用CPU工夫定义为自程序启动以来的GOMAXPROCS积分。 // 也就是说,如果GOMAXPROCS为2,并且程序运行了 // 10秒钟,那么它的“可用CPU”为20秒。GCCPUFraction // 不包含用于写入屏障流动的CPU工夫。 // // 这与GODEBUG=gctrace=1报告的CPU工夫雷同。 GCCPUFraction float64 // EnableGC 示意GC是否已启用。它始终为true, // 即便GOGC=off。 EnableGC bool //...}
2.2 示例代码
package mainimport ( "log" "runtime" "time")func readMemStats() { var ms runtime.MemStats runtime.ReadMemStats(&ms) log.Printf(" ===> Alloc:%d(bytes) HeapIdle:%d(bytes) HeapReleased:%d(bytes)", ms.Alloc, ms.HeapIdle, ms.HeapReleased)}func test() { //slice 会动静扩容,用slice来做堆内存申请 container := make([]int, 8) log.Println(" ===> loop begin.") for i := 0; i < 32*1000*1000; i++ { container = append(container, i) if ( i == 16*1000*1000) { readMemStats() } } log.Println(" ===> loop end.")}func main() { log.Println(" ===> [Start].") readMemStats() test() readMemStats() log.Println(" ===> [force gc].") runtime.GC() //强制调用gc回收 log.Println(" ===> [Done].") readMemStats() go func() { for { readMemStats() time.Sleep(10 * time.Second) } }() time.Sleep(3600 * time.Second) //睡眠,放弃程序不退出}
能够看到,打印[Done].之后那条trace信息,Alloc曾经降落,即内存已被垃圾回收器回收。在2020/03/02 18:21:38和2020/03/02 18:21:48的两条trace信息中,HeapReleased开始回升,即垃圾回收器把内存归还给零碎。
3. pprof工具收集性能指标
你能够应用 pprof 包来查看程序的内存状况。pprof 包提供了用于性能剖析的工具,包含查看内存分配情况的性能。pprof有两种形式获取程序运行数据的工具,别离对应两个规范库:
runtime/pprof: 采集工具型利用运行数据进行剖析net/http/pprof: 采集服务型利用运行时数据进行剖析// 如果要定制一些采集信息能够通过runtime开启runtime.SetBlockProfileRate(1) // 开启对阻塞操作的跟踪,block runtime.SetMutexProfileFraction(1) // 开启对锁调用的跟踪,mutex
3.1 服务型利用应用net/http/pprof
- 导入 net/http/pprof 包以及 net/http 包,以便启动一个HTTP服务器来提供 pprof 的 Web 接口。
import ( _ "net/http/pprof" "net/http")
在你的代码中增加一个HTTP服务器,以便可能通过Web接口拜访 pprof 数据
go func() { // 监听HTTP申请,启动一个HTTP服务器 // 留神:这是一个示例,你能够依据须要更改端口 http.ListenAndServe("localhost:6060", nil)}()
- 服务型的在浏览器中输出地址:http://127.0.0.1:6060/debug/pprof/,即可看到监控的数据。
3.2 工具型利用应用runtime/pprof
- 在你的代码中的适当地位导入 runtime/pprof 包并应用它来生成内存剖析数据。
import ( "runtime/pprof" "os")func main() { // 创立一个文件,用于存储内存剖析数据 memFile, _ := os.Create("memory.pprof") defer memFile.Close() // 开始内存剖析,将后果写入文件 pprof.WriteHeapProfile(memFile) // 你的利用程序代码}
3.3 剖析profile
3.3.1 工具型模式
执行go tool pprof app.profile
,会进入一个命令行交互页面,能够输出命令查看须要查看的信息.
3.3.2 服务端模式
- 形式一:
间接应用web服务接口数据go tool pprof http:127.0.0.1:6060/debug/pprof/profile?seconds=30
- 形式二:
先从web服务接口下载profile文件wget -O app.profile 'http:127.0.0.1:6060/debug/pprof/profile?seconds=30'
而后剖析下载profile文件,执行go tool pprof app.profile
,会进入一个命令行交互页面。
3.3.3 交互命令
执行go tool pprof app.profile
后,能够通过help来看反对的命令,比方输出help能够看到有top命令,通过输出top来查看cpu的性能状况.
//flat:以后函数占用CPU的耗时//flat::以后函数占用CPU的耗时百分比//sun%:函数占用CPU的耗时累计百分比//cum:以后函数加上调用以后函数的函数占用CPU的总耗时//cum%:以后函数加上调用以后函数的函数占用CPU的总耗时百分比//最初一列:函数名称(pprof) topShowing nodes accounting for 17.57s, 92.86% of 18.92s totalDropped 147 nodes (cum <= 0.09s)Showing top 10 nodes out of 48 flat flat% sum% cum cum% 15.62s 82.56% 82.56% 15.64s 82.66% runtime.cgocall 0.38s 2.01% 84.57% 0.48s 2.54% math/rand.(*Rand).Int31n 0.29s 1.53% 86.10% 16.52s 87.32% internal/poll.(*FD).writeConsole 0.25s 1.32% 87.42% 0.25s 1.32% runtime.unlock2 0.24s 1.27% 88.69% 0.35s 1.85% bytes.(*Buffer).Write 0.20s 1.06% 89.75% 0.31s 1.64% unicode/utf16.Encode 0.19s 1.00% 90.75% 0.19s 1.00% runtime._ExternalCode 0.16s 0.85% 91.60% 0.79s 4.18% math/rand.Intn 0.13s 0.69% 92.28% 0.19s 1.00% runtime.lock2 0.11s 0.58% 92.86% 0.11s 0.58% runtime.stdcall2(pprof)
4. 应用graphviz可视化
首先要下载graphviz, https://graphviz.org/download/ 装置对应的版本。
形式一: 这时候应用命令go tool pprof app.profile
, 输出web指令,就能够查看对应的其可视化的剖析后果了。
形式二:间接通过命令go tool pprof -http=:8080 app.profile
启动web在浏览器中可视化查看后果。