这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。本文介绍Go语言内存管理的问题及优化方法。
前言
性能优化是指提升软件系统处理的能力,减少不必要的消耗,充分发掘计算机算力。做性能优化的优点:不仅可以提高用户体验还能高效利用资源,降低成本。
业务代码层优化:针对特定场景,具体问题具体分析。语言运行时优化:解决更通用性的问题,考虑更多场景,可以使用Tradeoffs。
一、自动内存管理
1.自动内存管理-相关概念
动态内存:程序在运行时根据需求动态分配的内存
自动内存管理(垃圾回收):由程序语言运行时系统回收动态内存。其优点是程序员可以避免手动内存管理,专注于实现业务逻辑;保证内存使用的安全性和正确性。
Mutator:业务线程,分配新对象,修改对象指向关系
Collector:GC线程,找到存活对象,回收死亡对象的内存空间
Serial GC:只有一个collector
Parallel GC:支持多个collectors同时回收的GC算法
Concurrent GC:mutator和collector可以同时执行
2.追踪垃圾回收
-
对象被回收的条件是指针指向关系不可达的对象
-
标记根对象
- 静态变量、全局变量、常量、线程等
-
标记找到可达对象
- 求指针指向关系的传递闭包:从根对象出发,找到所有可达对象
-
清理所有不可达对象
- 将存活的对象复制到另外的内存空间(Copying GC)
- 将死亡对象的内存标记为可分配(Mark-sweep GC,使用free list管理空闲内存
- 移动并整理存活对象(Mark-compact GC),原地整理对象
二、Go内存管理及优化
优化方案 Balanced GC
- 每个g都绑定一个大块内存(1KB),称作goroutine allocation buffer(GAB)
- GAB用于noscan类型的小对象分配:< 128B
- 使用三个指针维护GAB:base,end,top
- Bump pointer(指针碰撞)风格对象匹配
- 无须和其他请求互斥
- 分配动作简单高效 GAB对于Go内存来说是一个对象
本质:将多个小对象的内存合并成一次对象的分配
问题:GAB的对象分配方式会导致内存被延迟释放
优化方案:移动GAB中存活的对象
- 当GAB总大小超过一定阈值时,将GAB中存活的对象复制到另外分配的GAB中
- 原先的GAB可以释放,避免内存泄露
- 本质:用copying GC 的算法管理小对象