当前位置: 首页>编程语言>正文

golang 好用的单机内存消息队列 golang内存优化

GPM调度模型

想要进行性能优化首先要了解最基础的底层模型

  • 一个 G 就是一个 goroutine,在 runtime 中通过类型 g 来表示。当一个 goroutine 退出时,g 对象会被放到一个空闲的 g 对象池中以用于后续的 goroutine 的使用(减少内存分配开销)。
  • 一个 M 就是一个系统的线程,系统线程可以执行用户的 go 代码、runtime 代码、系统调用或者空闲等待。在 runtime 中通过类型 m 来表示。在同一时间,可能有任意数量的 M,因为任意数量的 M 可能会阻塞在系统调用中。(当一个 M 执行阻塞的系统调用时,会将 M 和 P 解绑,并创建出一个新 的 M 来执行 P 上的其它 G。)
  • 最后,一个 P 代表了执行用户 go 代码所需要的资源,比如调度器状态、内存分配器状态等。在runtime 中通过类型 p 来表示。P 的数量精确地(exactly)等于 GOMAXPROCS。一个 P 可以被理 解为是操作系统调度器中的 CPU,p 类型可以被理解为是每个 CPU 的状态。调度器的工作是将一个 G(需要执行的代码)、一个 M(代码执行的地方)和一个 P(代码执行所需要 的权限和资源)结合起来。当一个 M 停止执行用户代码的时候(比如进入阻塞的系统调用的时候),就需要把它的 P 归还到空闲的 P 池中;为了继续执行用户的 go 代码(比如从阻塞的系统调用退出 的时候),就需要从空闲的 P 池中获取一个 P。 所有的 g、m 和 p 对象都是分配在堆上且永不释放的,所以它们的内存使用是很稳定的。得益于此 ,runtime 可以在调度器实现中避免写屏障(垃圾回收时需要的一种屏障,会带来一些性能开销)。

如何优化

slice 预分配内存优化

golang 好用的单机内存消息队列 golang内存优化,golang 好用的单机内存消息队列 golang内存优化_系统调用,第1张

map 预分配内存优化

golang 好用的单机内存消息队列 golang内存优化,golang 好用的单机内存消息队列 golang内存优化_golang 好用的单机内存消息队列_02,第2张

使用 strings.Builder 而不是 bytes.Buffer

函数中尽可能使用值而不是指针

● 使用指针会使逃逸分析将变量分配在堆上
● 分配在栈上的对象会随着栈销毁而回收,不会给 gc 带来压力
● 在栈上进行小对象拷贝的性能很好,比分配对象在堆上要好非常多
● 这个规则适用于函数接受者(receiver):指针仅仅应该用来表示“可修改权”,只有当方法会修改对象,并且修改后的值需要在方法外感知到时,才应该使用指针
● 适用于 slice 类型,如非必要,slice 不要包含指针。

map 存值而不是指针

使用 struct{} 优化

● 可以和普通 struct 一样操作
● 不占用空间
● 指向同一个内存地址(runtime.zerobase,编译器特殊优化)

使用 atomic 优化

单纯使用锁是调度系统锁

golang 好用的单机内存消息队列 golang内存优化,golang 好用的单机内存消息队列 golang内存优化_系统调用_03,第3张

使用原子化操作内存更低

golang 好用的单机内存消息队列 golang内存优化,golang 好用的单机内存消息队列 golang内存优化_golang_04,第4张

使用不带缓冲区的 channel

golang 好用的单机内存消息队列 golang内存优化,golang 好用的单机内存消息队列 golang内存优化_内存优化_05,第5张

一些工具

● go tool pprof
 ● go tool trace
 ● go build -gcflags=”-m”
 ● GODEBUG=”gctrace=1”
 ● go get benchmark



https://www.xamrdz.com/lan/5nc1962664.html

相关文章: