Go性能优化与内存管理 | 青训营

62 阅读4分钟

//为避免浪费时间,请尽快退出

内存管理

测试工具 Benchmark

支持基准性能测试 go test xxx -benchmen

slice

  • slice 预分配内存 尽可能在使用 make()初始化切片时提供容量信息
  • 大内存未释放 在已有切片基础上创建切片,不会创建新的底层数组 会复用原来切片的底层数组
  • 场景
    • 原切片较大,代码在原切片基础上新建小切片
    • 原底层数组在内存中有引用得不到释放
  • 可用 copy 替代 re-slice

map

  • 预分配内存
    • 不断向 map 中添加元素会触发扩容
    • 减少内存拷贝和 rehash 的消耗

字符串处理

拼接效率: strings. Buffer>strings. Builder \approx bytes. Buffer>+

  • 字符串在 go 语言中是不可变类型,占用内存大小固定
  • +每次回重新分配内存
  • bytes. Buffer,strings. Builder 底层是[]byte 数组,不需要每次重新分配内存

空结构体

节约内存

  • 空结构体 struct{}实例不占据任何的内存空间
  • 作为占位符使用
    • 节省资源
    • 本身具有很强语义

atomic 包

  • 锁的实现是通过操作系统,属于系统调用
  • atomic 操作是通过硬件实现,效率比锁高
  • sync. Mutex 应该用来保护一段逻辑,不仅仅用于保护一个变量
  • 对于非数值操作,可以使用 atomic. Value,能承载一个 interface{}

性能分析工具 pprof

用于可视化和分析性能分析数据的工具 go tool pprof -http=: 8080 "\http://localhost: 6060/debug/pprof/xxxx"

CPU

falt 当前函数本身的执行耗时 cum 当前函数本身加上其调用函数的总耗时

  • Flat==Cum, 函数中没有调用其他函数
  • Flat==0, 函数中只有其他函数的调用

命令:topN 功能:查看占用资源最多的函数

命令:list 功能:根据指定的正则表达式查找代码行

命令:web 功能:调用关系可视化

Heap-堆内存

goroutine-协程

goroutine 泄露会导致内存泄漏

mutex-锁

block-阻塞

threadcreate-线程创建

业务服务优化

流程

  1. 建立服务性能评估手段
  2. 分析性能数据,定位性能瓶颈
  3. 重点优化项改造
    • 正确性是基础
    • 响应数据 diff
      • 线上请求数据录制回放
      • 新旧逻辑接口数据 diff(差异)
  4. 优化效果验证

自动内存管理

  • 动态内存
    • 程序在运行时根据需求动态分配内存:malloc ()
  • 自动内存管理(垃圾回收):由程序语言的运行时系统管理动态内存
    • 避免手动内存管理,专注于实现业务逻辑
    • 保证内存使用的正确性和安全性:避免double-free probledm, use-after-free problem
  • 三个任务
    • 为新对象分配空间
    • 找到存活对象
    • 回收死亡对象的内存空间

相关概念

Mutator:业务线程,分配新对象,修改对象指向关系 Collector:GC 线程,找到存活对象,回收死亡对象的内存空间 Serial GC:只有 collector Parallel GC:支持多个 collectors 同时回收的 GC 算法 Concurrent GC:mutator (s)和 collector (s)可以同时执行

垃圾回收

  • 对象被回收条件:指针指向关系不可达的对象
  • 标记根对象
    • 静态变量,全局变量,常量,线程栈
  • 标记:找到可达对象
    • 求指针指向关系的传递闭包:从根对象出发,找到所有可达对象
  • 清理:所有不可达对象
    • 将存活对象复制到另外的内存空间
    • 将死亡对象的内存标记为可分配
    • 移动并整理存活对象
  • 根据对象的生命周期,使用不同的标记和清理策略

内存分配

分块

目标:为对象在 heap 上分配内存 提前将内存分块,根据对象大小选择合适块

  1. mmap()申请内存
  2. 将内存划分成大块,mspan
  3. 划分成特定大小小块

noscan mspan:分配不包含指针的对象——GC 不需要扫描 scan mspan:分配包含指针的对象——GC 需要扫描

缓存

g->m->p->mcache 用于快速分配,为绑定于 p \downarrow 上的 g 分配对象 memory block<-mspan
当 mcache 中的 mspan 分配完毕,向 mcentral 申请带有未分配块的 mspan 当 mspan 中没有分配对象,mspan 会被缓存在 mcentral 中,而不是立即释放。

Balanced GC

本质:将多个小对象的分配合并成一个大对象的分配 问题:GAB 的对象分配方式会导致内存被延迟释放 解决方案:移动 GAB 中存活的对象

  • 当总大小超过一定阈值时,将 GAB 存活对象复制到另外分配的 GAB 中
  • 原先的 GAB 可以释放
  • 本质:copying GC 管理小对象

Beast mode 提升代码性能