通过 Go 应用内存诊断功能,对 Go 进程的内存使用情况进行深度分析和界定。本文介绍了 Go 应用内存诊断功能的使用说明。
功能概述
Go 应用内存诊断是内存诊断项下的重要功能,支持对 Go 进程的堆内存、非堆内存、goroutine、线程等进行全面分析,帮助定位内存泄漏、内存碎片、非 Go 堆占用过高等问题。
使用场景
场景 | 说明 |
Go 堆内存占用偏高 | Go 进程的堆内存(inUseSpan)持续增长,导致实际内存占用超出预期 |
Go 释放不及时/碎片化 | Go 内存释放不及时,deadSpan 或 manualSpan 占比异常,内存碎片严重 |
非 Go 堆占用过高 | Go 进程的非堆内存(nonAnonPageMem)占比过高,如文件映射、CGO 调用等 |
前提条件
目标实例已安装并运行 Go 应用
已知目标 Go 进程的 PID
如果您使用 RAM 用户,请确保阿里云账号(主账号)已将系统策略 AliyunECSReadOnlyAccess 和 AliyunSysomFullAccess 授予 RAM 用户
已开通操作系统控制台权限
操作步骤
访问 操作系统控制台,在页面左侧顶部,选择目标实例所在的地域。
在左侧导航栏,单击系统诊断。
诊断模式选择节点诊断,诊断类型列表中,选择内存诊断。在诊断项列表中,选择Golang内存诊断。
配置诊断参数:
参数名
参数说明
是否必填
实例 ID
目标 ECS 实例 ID
是
进程 PID
目标 Go 进程的 PID
是
配置好相关参数后,单击执行诊断,系统将自动执行诊断并生成诊断报告。
在诊断记录区域,在操作列单击查看报告,即可看到完整的诊断报告。
诊断报告
基础信息
基础信息部分包含单次诊断的基本信息,包括:
字段 | 说明 |
诊断实例 ID | 被诊断实例的资源 ID |
诊断项 | Go 应用内存诊断(gomemdump) |
诊断报告 ID | 本次诊断的唯一标识 |
诊断发起时间 | 诊断任务发起的时间 |
Go 版本 | 目标进程运行的 Go 版本 |
可执行文件 | Go 进程的可执行文件路径 |
进程 PID | 目标 Go 进程的进程 ID |
诊断完成时间 | 诊断任务完成的时间 |
诊断结论
该部分展示本次诊断的结论,详细描述 Go 进程内存使用的主要原因。根据实际诊断结果,可能包含以下结论:
Go 堆内存占用偏高:Go 进程的 inUseSpan 占比异常高,可能存在内存泄漏或对象分配过多
Go 释放不及时/碎片化:Go 内存释放不及时,deadSpan 或 manualSpan 占比异常
非 Go 堆占用过高:非匿名页面内存(nonAnonPageMem)占比过高,存在大量文件映射或 CGO 调用
当前系统状态正常,无需干预:Go 进程内存使用正常,无明显异常
诊断建议
根据诊断结果,提出相应的处理建议。以下是一些常见场景的建议:
Go 堆内存占用偏高
检查是否存在未释放的大对象或 goroutine 泄漏
使用 pprof 进行深度分析,定位内存分配热点
考虑使用 sync.Pool 进行对象池复用
检查是否有不必要的闭包捕获导致内存无法释放
Go 释放不及时/碎片化
调整 GODEBUG 参数,如设置
madvdontneed=1加快内存归还检查频繁分配释放小对象的代码
考虑使用 sync.Pool 减少内存碎片
定期触发 runtime.GC() 加速内存回收
非 Go 堆占用过高
检查是否有大文件 mmap 映射未释放
分析 CGO 调用的内存分配情况
检查是否有未关闭的文件描述符
优化文件读取方式,避免全量加载到内存
诊断详情
诊断详情部分提供详细的内存分析数据,包括以下几个维度:
1. Go 进程信息
展示 Go 进程的基本信息:
PID:Go 进程 ID
Go 版本:运行时的 Go 版本(如 go1.20.5)
可执行文件路径:Go 进程的可执行文件完整路径
诊断时间:执行诊断的时间
2. Go 内存使用详情
展示了Go进程内存使用详情:
操作系统内存使用情况
go进程内的分配情况
非匿名页内的分配情况
常见问题
如何获取 Go 进程的 PID?
可以通过以下命令获取 Go 进程的 PID:
# 方法一:通过进程名查找
ps aux | grep <go程序名>
# 方法二:通过端口查找(如果 Go 程序监听了特定端口)
lsof -i :<端口号>
# 方法三:如果程序自己打印了 PID
# 可以在程序启动时添加:fmt.Printf("PID: %d\n", os.Getpid())Go 内存诊断和 OOM 诊断有什么区别?
OOM 诊断:针对系统发生 Out Of Memory 事件时的诊断,分析 OOM 的原因(系统内存不足、cgroup 内存超限等)
Go 内存诊断:针对 Go 进程的日常内存使用分析,无需等待 OOM 事件,可随时对指定 Go 进程进行诊断
Go 内存诊断支持哪些 Go 版本?
Go 内存诊断支持 Go 1.18 及以上版本。建议使用较新的 Go 版本以获得更好的诊断效果。
诊断过程中会影响 Go 进程的运行吗?
诊断过程通过读取 /proc 文件系统和 Go runtime 的调试信息来实现,对 Go 进程的性能影响小。
如果诊断失败怎么办?
请检查以下几点:
确认目标实例的 SysOM 已正确安装
确认 PID 对应的进程确实存在且为 Go 进程
确认当前用户有足够的权限访问目标实例
查看诊断记录中的错误信息,根据提示进行排查