Memory 当声明非常大的数组并在stdin上迭代时,连续内存会增加
下面的代码声明了两个数组,然后在stdin上迭代(只是盲目地在文件上迭代-与数组没有交互) 这会导致内存不断增加 然而,如果我只声明两个数组和sleep,内存不会增加 类似地,如果我只是在stdin上迭代-内存没有增加 但总的来说(除了为阵列分配的内存之外)会不断增加 我通过使用top工具查看RES内存来测量这一点 我已经注释掉了Memory 当声明非常大的数组并在stdin上迭代时,连续内存会增加,memory,go,Memory,Go,下面的代码声明了两个数组,然后在stdin上迭代(只是盲目地在文件上迭代-与数组没有交互) 这会导致内存不断增加 然而,如果我只声明两个数组和sleep,内存不会增加 类似地,如果我只是在stdin上迭代-内存没有增加 但总的来说(除了为阵列分配的内存之外)会不断增加 我通过使用top工具查看RES内存来测量这一点 我已经注释掉了func doSomething()中的前几行,以表明在注释时没有内存增加。取消对行的注释并运行将导致增加 注:这是在go 1.4.2、1.5.3和1.6上运行的 注意
func doSomething()
中的前几行,以表明在注释时没有内存增加。取消对行的注释并运行将导致增加
注:这是在go 1.4.2、1.5.3和1.6上运行的
注意:您将需要在至少有16GB RAM的机器上重新创建它,因为我只在10亿大小的阵列上观察到了这一点
主程序包
进口(
“布菲奥”
“fmt”
“io”
“操作系统”
)
类型MyStruct struct{
arr1[]整数
arr2[]整数
}
func(ms*MyStruct)Init(size int,arr1[]int,arr2[]int)错误{
fmt.Printf(“初始化mystruct arr1…\n”)
ms.arr1=arr1
如果ms.arr1==nil{
ms.arr1=make([]整数,大小,大小)
}
fmt.Printf(“初始化mystruct arr2…\n”)
ms.arr2=arr2
如果ms.arr2==nil{
ms.arr2=make([]整数,大小,大小)
}
fmt.Printf(“完成初始化…\n”)
对于i:=0;i
wgethttp://pastebin.com/raw/QfG22xXk -哦,坏家伙,走
是“1234567890”|快跑坏箱子。快跑
wgethttp://pastebin.com/raw/G9xS2fKy -哦,古德凯斯,走吧
是“1234567890”|开始运行goodcase.go
感谢您的上述评论。我想捕捉调试这个的过程作为一个答案
REStop/htop
只是在进程级别告诉您内存中发生了什么。GODEBUG=“gctrace=1”可以让您更深入地了解内存的处理方式
使用gctrace集进行简单的运行可以得到以下结果
root@localhost ~ # yes "12345678901234567890123456789012" | GODEBUG="gctrace=1" go run badcase.go
starting...
allocating
initializing mystruct arr1...
initializing mystruct arr2...
gc 1 @0.050s 0%: 0.19+0.23+0.068 ms clock, 0.58+0.016/0.16/0.25+0.20 ms cpu, 7629->7629->7629 MB, 7630 MB goal, 8 P
done initializing ...
gc 2 @0.100s 0%: 0.070+2515+0.23 ms clock, 0.49+0.025/0.096/0.24+1.6finished allocating..1000000000 1000000000
ms cpu, 15258->15258reading from stdin...
->15258 MB, 15259read 0 lines...
MB goal, 8 P
gc 3 @2.620s 0%: 0.009+0.32+0.23 ms clock, 0.072+0/0.20/0.11+1.8 ms cpu, 15259->15259->15258 MB, 30517 MB goal, 8 P
read 1000000 lines...
read 2000000 lines...
read 3000000 lines...
read 4000000 lines...
....
read 51000000 lines...
read 52000000 lines...
read 53000000 lines...
read 54000000 lines...
这是什么意思
如您所见,gc已经有一段时间没有被调用了。这意味着从reader.ReadString生成的所有垃圾尚未收集和释放
为什么垃圾收集器不收集这些垃圾
从
相反,我们提供了一个单独的旋钮,称为GOGC。此值控制
相对于可访问对象的大小,堆的总大小。
默认值100意味着堆的总大小现在增加了100%
大于(即,两倍)最后一次之后可到达对象的大小
收藏
由于未设置GOGC,默认值为100%。因此,它只有在达到~32GB时才会收集垃圾。(因为最初这两个数组为您提供16GB的堆空间-只有当堆加倍时,gc才会触发)
我怎样才能改变这个?
尝试将GOGC设置为25
以GOGC为25
root@localhost ~ # yes "12345678901234567890123456789012" | GODEBUG="gctrace=1" GOGC=25 go run badcase.go
starting...
allocating
initializing mystruct arr1...
initializing mystruct arr2...
gc 1 @0.051s 0%: 0.14+0.30+0.11 ms clock, 0.42+0.016/0.31/0.094+0.35 ms cpu, 7629->7629->7629 MB, 7630 MB goal, 8 P
done initializing ...
finished allocating..1000000000 1000000000
gc 2 @0.102s reading from stdin...
12%: 0.058+2480+0.26 ms clock, 0.40+0.022/2480/0.10+1.8 ms cpu, 15258->15258->15258 MB, 15259 MB goal, 8 P
read 0 lines...
gc 3 @2.584s 12%: 0.009+0.20+0.22 ms clock, 0.075+0/0.24/0.046+1.8 ms cpu, 15259->15259->15258 MB, 19073 MB goal, 8 P
read 1000000 lines...
read 2000000 lines...
read 3000000 lines...
read 4000000 lines...
....
read 19000000 lines...
read 20000000 lines...
gc 4 @6.539s 4%: 0.019+2.3+0.23 ms clock, 0.15+0/2.1/12+1.8 ms cpu, 17166->17166->15258 MB, 19073 MB goal, 8 P
如您所见,触发了另一个gc
但top/htop显示其稳定在约20GB,而不是计算的16GB
垃圾收集器“不必”将其返回操作系统。它有时会保留它以便将来有效地使用。它不必不断地从操作系统中获取和回馈—在再次询问操作系统之前,额外的4 gb空间就在其可用空间池中。如何衡量“内存增加”以及您所谈论的内存类型。很可能一切都很好;略读你的代码看起来没问题。当然,如果分配20亿个整数,代码将消耗更多内存,因为这至少是8GB。@Volker我启动了一个htop并监视RES内存。是的,在64位机器上,启动时大约需要16GB,但当我开始从stdin读取数据时,它就会迅速上升,并且永不停止。(更新问题以反映评论)。你确定它真的不会停止吗?要了解记忆,请特别关注GODEBUG和gctrace,这比(h)更有帮助top@Volker只是确认一下——这个过程中RES的持续增加确定了内存正在增加的事实。我将不得不使用godebug和gctrace来找出原因,对吗?另外,“并没有真正停止”是我假设的,当它从16(它应该是什么)增加到32 Gig(我的ram限制)之后,它进入了交换,所以我杀死了它。要查看操作系统htop提供给它的内存发生了什么以及Go做了什么是不够的。使用GODEBUG=“gctrace=1”查看Go的垃圾收集器的“内部”。您可能会发现GC没有“足够频繁地”运行:这是