提问:Go 指针(Go Pointer)真的是性能优化?

在过去的几周,我已经回复了许多关于指针优化性能的问题或结论。毕竟这是一个复杂的事情,难免让人感到迷惑。我希望这边文章能够帮助大家找打答案。

答案:指针生来不是优化性能的。

其中细节不做过多赘述,容易让人厌倦,主要描述其中概念。

要点: 本文讨论的性能是微优化。微优化离不开实际性能优化的基准测试。要始终选择最易理解的解决方案 。

什么是指针?

简单来说,指针就是内存地址。要访问所指向的值,程序通过地址找到值的开始位置。这被称为「解引用」。

怎样使用指针来优化?

将变量传递给函数时,会将变量的拷贝提供给被调用函数。 在大多数情况下,指针会比指向的值小。

通常,指针与系统架构的大小相同,在 32 位系统上为 32 位,在 64 位系统上为 64 位。 如果参数是标量类型(boolintfloat 等),它将小于或等于指针的大小。 如果参数是复合类型,例如具有多个字段的struct,则指针会比参数更小。

因此,复制指针比复制指针所指向的值更高效。 的确如此,但在某种程度上涉及性能这里要考虑的点比单纯内存复制多得多。

指针有副作用吗?

两点:

  1. 解除指针不是无消耗的,不是一个大的消耗,但是消耗是递增的。
  2. 通过指针共享数据使得数据存储在 “堆” 中。堆是一段内存,存放比单个函数调用时间更长的数据。向堆中添加数据是有消耗的,堆中的数据只能被垃圾回收机制清除。堆中数据越多,垃圾回收机制要做的也就越多,对应用的影响也就越大。

栈 vs 堆

栈和堆都很重要。下面进行简要说明。不用担心好不好理解。

栈:函数内存

函数每次调用都会在栈中分配一段区域来存储内部变量。函数栈的大小是编译时确定的。函数调用时,会分配一段空闲栈内存。当函数返回时,这个栈内存可用于下一次函数调用,这不需要额外的清理。虽然不是无消耗的,但成本特别低。

堆:数据共享区

如上所述,函数内的变量在函数返回时就 “消失” 了。如果都是非指针值返回这是没有什么问题的,因为返回值复制到了调用函数的栈中。

但是,如果返回的是指针,指针所指向的数据需要存放在栈以外的地方,这样才不会 “消失” 。那就是堆了。

这有一些与堆相关的性能问题:

  1. 堆中存放数据需要在运行时请求内存。消耗不大不小。
  2. 如果没有足够的堆空间,运行时会请求系统内存,增加消耗。
  3. 一旦值被存放在堆中,它会一直待到没有函数调用它。当没有指针指向这些数据时,需要清除。在 Go 中,垃圾回收机制来清除。它会找到多有的没有被引用的值,释放在堆中的空间。堆中的值越多,垃圾回收所做的工作也就越多,对应用的潜在影响也就越大。

为什么使用指针?

指针可以共享数据。如果需要函数修改传入的数据,指针式可行的。

指针还可以区分零值和未设置的值。

结论

指针可以避免内存复制,但是纠结点在额外的间接性和垃圾回收成本。在我看来,在确认应用是因为值复制出现问题之前,不需要考虑这个。电脑内存复制时非常快的。

希望你能从这边文章意识到指针很有用,但是不能因为觉得能够带来更好的表现而使用。

默认使用值,除非需要使用指针的特性。

注意:

  • 文章简化了许多概念,让其简单易懂
  • 没有涉及的概念有:逃逸分析,接口转换,內联函数,栈增长。
  • 许多类型,例如 slices ,strings , 和 maps,都包含指向底层数据的指针,对这些类型传指针时没有多大意义的。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://medium.com/@vCabbage/go-are-poin...

译文地址:https://learnku.com/go/t/61054

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!