如何最大限度地减少Go中的垃圾收集?

时间:2012-09-05 08:33:20

标签: garbage-collection go

有时你可能想避免/最小化垃圾收集器,所以我想确定如何做到这一点。

我认为下一个是正确的:

  • 在函数开头声明变量。
  • 使用数组而不是切片。

还有吗?

2 个答案:

答案 0 :(得分:32)

要最小化Go中的垃圾收集,必须最小化堆分配。要最小化堆分配,您必须了解分配何时发生。

以下内容总是导致分配(至少在Go 1中的gc编译器中):

  • 使用new内置功能
  • 使用make内置函数(少数几个角落情况除外)
  • 当值类型是切片,地图或具有&运算符的结构
  • 时的复合文字
  • 将大于机器字的值放入接口。 (例如,字符串,切片和某些结构比机器字大。)
  • string[]byte[]rune之间转换
    • 从Go 1.3开始,编译器特殊情况下此表达式不分配: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,则仍在重置它,但保留旧数组。

在大多数情况下,尝试避免创建垃圾是过早优化。对于您的大部分代码而言无关紧要。但是你可能偶尔会发现一个被称为很多次的函数,它每次运行时分配很多。或者重新分配而不是重用的循环。我会等到你看到瓶颈然后才能过火。