golang gc优化

目录

  • gc 原理
  • 对象分配在堆还是栈?
  • 怎么评价gc结果好坏?
  • 有用的技巧?
      • 有效的监控与告警
      • 控制应用的总体堆内存大小
      • 合理使用指针以及逃逸分析
      • 优化string与[]byte相互转换
      • 大量的string拼接,可以考虑用 bytes.Buffer
      • 避免频繁小对象申请

gc 原理

可以参考几篇文章

  • golang gc原理,比较容易讲清楚三色标记
    https://making.pusher.com/golangs-real-time-gc-in-theory-and-practice/
  • 比较详细的gc过程 golang垃圾回收浅析

回顾一下基本的问题:
3. gc回收什么内存?
目标是回收堆上的内存。
4. 什么样的对象会分配在堆?
参考 对象分配在堆还是栈?,

对象分配在堆还是栈?

https://golang.org/doc/faq#stack_or_heap
摘录一段原话:
How do I know whether a variable is allocated on the heap or the stack?
From a correctness standpoint, you don’t need to know. Each variable in Go exists as long as there are references to it. The storage location chosen by the implementation is irrelevant to the semantics of the language.

The storage location does have an effect on writing efficient programs. When possible, the Go compilers will allocate variables that are local to a function in that function’s stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors. Also, if a local variable is very large, it might make more sense to store it on the heap rather than the stack.

In the current compilers, if a variable has its address taken, that variable is a candidate for allocation on the heap. However, a basic escape analysis recognizes some cases when such variables will not live past the return from the function and can reside on the stack.

一般上,开发者并不需要知道对象是分配在堆或者栈,因为没有明确的规则。一个非常大的临时变量也会有限分配在堆上。
由于内存逃逸是在编译阶段确定的,可以通过编译参数确定函数的对象是否发生逃逸,go build -gcflags "-m -l" *.go

怎么评价gc结果好坏?

没有很明确的答案,想一下gc的本质,是为了防止堆内存泄露的措施。

golang gc用的方法还是mark & sweep方法,
与之相关的一些因素:

  1. 堆内存的总量越大,gc时间越长
  2. 堆中的待回收内存总量越大,gc时间越长

比较大的准则是业务约束,比如fps游戏,gc时间如果超过30ms,那就可能导致少处理一个帧。或者某些api有最大延时限制。

有用的技巧?

事实上,没有很通用的准则,但可以从以下点入手

有效的监控与告警

开发者首先需要知道gc的表现,表现不符合预期的时候需要干预

控制应用的总体堆内存大小

  1. 数据冷热分离,冷数据定时清理;
  2. 按照合理的颗粒度微服务化,保持应用总体不会处理太复杂的业务;

合理使用指针以及逃逸分析

为了控制堆内存的大小

优化string与[]byte相互转换

可以考虑unsafe pointer

大量的string拼接,可以考虑用 bytes.Buffer

避免频繁小对象申请

看是否有合并成大对象的可能

你可能感兴趣的:(golang)