我写了一个使用golang编程的程序,在运行时使用了1.2GB的内存。
调用go tool pprof http://10.10.58.118:8601/debug/pprof/heap
只能得到仅有323.4MB堆使用量的转储。
- 剩下的内存使用情况如何?
- 是否有更好的工具来解释golang运行时内存?
使用gcvis
我得到了这个:
.. 和这个堆分析结果:
这是我的代码:https://github.com/sharewind/push-server/blob/v3/broker
我写了一个使用golang编程的程序,在运行时使用了1.2GB的内存。
调用go tool pprof http://10.10.58.118:8601/debug/pprof/heap
只能得到仅有323.4MB堆使用量的转储。
使用gcvis
我得到了这个:
.. 和这个堆分析结果:
这是我的代码:https://github.com/sharewind/push-server/blob/v3/broker
http://10.10.58.118:8601/debug/pprof/
的堆链接,将显示堆分析的调试视图,其中在底部有一个runtime.MemStats 结构的打印输出。Sys和操作系统报告之间仍然会存在差异,因为Go请求系统的内容与操作系统提供的内容并不总是相同的。此外,CGO/syscall(例如:malloc/mmap)内存不会被Go跟踪。
/debug/pprof/heap
没有运行时MemStats结构的打印输出。 - IanB--alloc_space
选项。
go tool pprof
默认使用--inuse_space
。它会抽样内存使用情况,因此结果是实际使用情况的子集。--alloc_space
,pprof返回自程序启动以来分配的所有内存。对于那些懂俄语的人,我做了一个演示并写了几篇关于这个主题的文章:
我一直对我的Go应用程序不断增长的住宅内存感到困惑,最后我不得不学习Go生态系统中存在的分析工具。运行时提供了许多度量标准,其中包括runtime.Memstats结构,但是很难理解哪些度量标准可以帮助找出内存增长的原因,因此需要一些额外的工具。
分析环境
在你的应用程序中使用 https://github.com/tevjef/go-runtime-metrics。例如,你可以将以下内容放入你的 main
函数中:
import(
metrics "github.com/tevjef/go-runtime-metrics"
)
func main() {
//...
metrics.DefaultConfig.CollectionInterval = time.Second
if err := metrics.RunCollector(metrics.DefaultConfig); err != nil {
// handle error
}
}
docker run --name influxdb -d -p 8086:8086 influxdb
docker run -d -p 9090:3000/tcp --link influxdb --name=grafana grafana/grafana:4.1.0
建立Grafana
和InfluxDB
之间的交互:Grafana
(Grafana主页 ->左上角 ->数据源 ->添加新数据源):
从 https://grafana.com 导入仪表盘 #3242 (Grafana主页 -> 左上角 -> 仪表盘 -> 导入):
最后,启动您的应用程序:它将向容器化的Influxdb
传输运行时指标。将您的应用程序置于合理的负载下(在我的情况下,它非常小-每秒5个请求数持续几个小时)。
内存消耗分析
Sys
(RSS
的同义词)曲线与HeapSys
曲线非常相似。结果发现动态内存分配是整体内存增长的主要因素,因此堆栈变量所消耗的少量内存似乎是恒定的,可以忽略;HeapIdle
以与Sys
相同的速度增长,而HeapReleased
始终为零。显然,在这个测试条件下,运行时根本不会将内存返回给操作系统。HeapIdle minus HeapReleased estimates the amount of memory that could be returned to the OS, but is being retained by the runtime so it can grow the heap without requesting more memory from the OS.
对于那些试图调查内存消耗问题的人,我建议按照以下步骤排除一些琐碎的错误(例如goroutine泄漏)。
显式释放内存
有趣的是,通过显式调用debug.FreeOSMemory()
可以显著减少内存消耗:
// in the top-level package
func init() {
go func() {
t := time.Tick(time.Second)
for {
<-t
debug.FreeOSMemory()
}
}()
}
事实上,与默认条件相比,这种方法节省了约35%的内存。
声明:我为 StackImpact 工作
--alloc_space
,这不适用于内存泄漏检测。它只会显示自程序启动以来分配了多少内存。对于长时间运行的程序,这些数字可能会变得非常高。到目前为止,我们还没有发现 StackImpact 代理中存在任何内存泄漏问题。 - logix尝试使用Tracy的GO插件。Tracy是“实时、纳秒级分辨率、远程遥测”工具(...)。GoTracy(插件名称)是与Tracy连接并发送必要信息以更好地了解您的应用程序过程的代理。导入插件后,您可以像下面的描述中一样放置遥测代码:
func exampleFunction() {
gotracy.TracyInit()
gotracy.TracySetThreadName("exampleFunction")
for i := 0.0; i < math.Pi; i += 0.1 {
zoneid := gotracy.TracyZoneBegin("Calculating Sin(x) Zone", 0xF0F0F0)
gotracy.TracyFrameMarkStart("Calculating sin(x)")
sin := math.Sin(i)
gotracy.TracyFrameMarkEnd("Calculating sin(x)")
gotracy.TracyMessageLC("Sin(x) = "+strconv.FormatFloat(sin, 'E', -1, 64), 0xFF0F0F)
gotracy.TracyPlotDouble("sin(x)", sin)
gotracy.TracyZoneEnd(zoneid)
gotracy.TracyFrameMark()
}
}
插件位于: https://github.com/grzesl/gotracy
Tracy 位于: https://github.com/wolfpld/tracy
尝试回答以下原始问题:
有没有更好的工具来解释golang运行时内存?
我发现以下工具很有用:
Statsview https://github.com/go-echarts/statsview Statsview将标准的net/http/pprof集成在一起。
Statsviz https://github.com/arl/statsviz
pprof
,他们的问题与为什么总内存使用量与pprof
堆报告的内存使用量存在差异有关。 - craigb