有时你可能想避免/最小化垃圾收集器,所以我想确定如何做到这一点。
我认为下一个是正确的:
还有吗?
答案 0 :(得分:32)
要最小化Go中的垃圾收集,必须最小化堆分配。要最小化堆分配,您必须了解分配何时发生。
以下内容总是导致分配(至少在Go 1中的gc编译器中):
new
内置功能make
内置函数(少数几个角落情况除外)&
运算符的结构string
,[]byte
和[]rune
之间转换
m[string(b)]
,其中m
是地图而b
是[]byte
string
defer
陈述go
陈述以下内容可以导致分配,具体取决于具体细节:
a.b()
不是指针且a
方法具有指针接收器类型,a
可能会取b
的地址。append
内置功能该列表旨在完成,我对此有合理的信心,但我很乐意考虑添加或更正。
如果您不确定分配的位置,您可以随时按其他人的建议进行分析,或者查看编译器生成的程序集。
答案 1 :(得分:22)
避免垃圾相对简单。您需要了解分配的位置,并查看是否可以避免分配。
首先,在函数开头声明变量无济于事。编译器不知道区别。然而,人类会知道它们之间的区别,它会使它们烦恼。
使用数组而不是切片将起作用,但这是因为数组(除非取消引用)被放在堆栈上。数组有其他问题,例如它们是通过函数之间的值(复制)传递的。堆栈上的任何内容都是“非垃圾”,因为它会在函数返回时被释放。可以转义函数的任何指针或切片都放在垃圾收集器必须处理的堆上。
你能做的最好的事情是避免分配。当您完成了大量不需要的数据时,请重用它们。这是Go博客上profiling tutorial中使用的方法。我建议阅读它。
除了分析教程中的另一个示例之外:假设您有一个名为[]int
的{{1}}类型的片段。你不断追加到xs
,直到你达到一个条件,然后你重置它,这样你就可以重新开始。如果执行[]int
,则现在将切片的基础数组声明为要收集的垃圾。然后,Append将在您下次使用时重新分配xs。如果您执行xs = nil
,则仍在重置它,但保留旧数组。
在大多数情况下,尝试避免创建垃圾是过早优化。对于您的大部分代码而言无关紧要。但是你可能偶尔会发现一个被称为很多次的函数,它每次运行时分配很多。或者重新分配而不是重用的循环。我会等到你看到瓶颈然后才能过火。