【发布时间】:2017-03-23 14:13:49
【问题描述】:
我需要你的智慧。
我有一个用 Go 编写的巨大守护进程。前段时间有用户报告说代码某处可能存在内存泄漏。
我开始调查这个问题。当主要代码检查没有让我找到有关此泄漏性质的任何线索时,我试图专注于我的流程是如何工作的。
我的想法很简单:如果我未能删除对某些对象的引用,我的堆应该会不断增长。我编写了以下程序来监控堆:
func PrintHeap() {
ticker := time.NewTicker(time.Second * 5)
for {
<-ticker.C
st := &runtime.MemStats{}
runtime.ReadMemStats(st)
// From Golang docs: HeapObjects increases as objects are allocated
// and decreases as the heap is swept and unreachable objects are
// freed.
fmt.Println("Heap allocs:", st.Mallocs, "Heap frees:",
st.Frees, "Heap objects:", st.HeapObjects)
}
}
此过程每 5 秒打印一些有关堆的信息,包括当前分配的对象数。
现在谈谈守护进程的作用。它处理来自某些 UDP 输入的行。每行都包含有关某个 HTTP 请求的一些信息,并被解析为典型的 Go 结构。这个结构有一些数字和字符串字段,包括一个请求路径。然后这个结构发生了很多事情,但这些事情在这里无关紧要。
现在,我将输入速率设置为每秒 1500 行,每行都相当短(您可以将其解读为:使用标准请求路径,/)。
运行应用程序后,我可以看到堆大小在某个时间点稳定:
Heap allocs: 180301314 Heap frees: 175991675 Heap objects: 4309639
Heap allocs: 180417372 Heap frees: 176071946 Heap objects: 4345426
Heap allocs: 180526254 Heap frees: 176216276 Heap objects: 4309978
Heap allocs: 182406470 Heap frees: 177496675 Heap objects: 4909795
Heap allocs: 183190214 Heap frees: 178248365 Heap objects: 4941849
Heap allocs: 183302680 Heap frees: 178958823 Heap objects: 4343857
Heap allocs: 183412388 Heap frees: 179101276 Heap objects: 4311112
Heap allocs: 183528654 Heap frees: 179181897 Heap objects: 4346757
Heap allocs: 183638282 Heap frees: 179327221 Heap objects: 4311061
Heap allocs: 185609758 Heap frees: 181330408 Heap objects: 4279350
当达到这个状态时,内存消耗停止增长。
现在,我更改了输入,使每行的长度超过 2k 个字符(带有巨大的 /AAAAA... 请求路径),这就是奇怪的事情开始发生的地方。
堆大小急剧增长,但一段时间后仍变得稳定:
Heap allocs: 18353000513 Heap frees: 18335783660 Heap objects: 17216853
Heap allocs: 18353108590 Heap frees: 18335797883 Heap objects: 17310707
Heap allocs: 18355134995 Heap frees: 18336081878 Heap objects: 19053117
Heap allocs: 18356826170 Heap frees: 18336182205 Heap objects: 20643965
Heap allocs: 18366029630 Heap frees: 18336925394 Heap objects: 29104236
Heap allocs: 18366122614 Heap frees: 18336937295 Heap objects: 29185319
Heap allocs: 18367840866 Heap frees: 18337205638 Heap objects: 30635228
Heap allocs: 18368909002 Heap frees: 18337309215 Heap objects: 31599787
Heap allocs: 18369628204 Heap frees: 18337362196 Heap objects: 32266008
Heap allocs: 18373482440 Heap frees: 18358282964 Heap objects: 15199476
Heap allocs: 18374488754 Heap frees: 18358330954 Heap objects: 16157800
但是内存消耗却在不断增长,而且从未停止过。我的问题是:关于发生了什么的任何想法?
我想过由于大量巨大的对象而导致的内存碎片,但实际上我真的不知道该怎么想。
【问题讨论】:
-
尝试打印
runtime.NumGoroutine。 Goroutine 泄漏是迄今为止最常见的内存消耗问题。 -
但是没有创建新的 goroutines,请求被放入一个循环缓冲区,该缓冲区被一个相同的例程定期清空。但是,是的,我会努力的。
-
尝试打印 st.Sys?
-
你使用哪个 go 版本?我在 1.3 和 1.4 中遇到了类似的问题
-
@apxp 是 go 版本 go1.7.4 linux/amd64
标签: go memory heap-memory