记一次因日志而引发的OOM问题

寒江蓑笠翁大约 4 分钟问题记录gopprof内存分析

记一次因日志而引发的OOM问题


问题

在最近的项目中,后端隔三岔五就会因为内存爆满而崩溃,这种情况差不多两三天就会发生一次。由于在项目中在向Steam请求模组信息时会开启多个协程并发请求,因此猜测可能是因为协程未能正常退出而导致的内存泄露问题,于是便通过pprof来对应用进行性能分析。

$ go tool pprof -http=:8080 http://127.0.0.1:9090/debug/pprof/heap

通过对pprof的可视化分析,发现与猜测的结果并不一致,在分析的过程中,发现获取服务端状态的这个接口在调用时内存占用会猛增,该接口主要用于判断游戏服务端是否启动,判断的逻辑就是去读取游戏服务端的日志文件,而有些用户的游戏服务端会一直开着,导致其文件大小可能会非常大,目前最大的发现有800MB,由于在读日志的时候是将其全量加载到内存中,那么这样一来就会导致内存占用升高。

图片已脱敏
图片已脱敏

并且在日志读取完后还要对其进行处理,由于go语言的字符串写时复制特性限制,在处理日志的时候还会拷贝一份副本,分配的内存就会更大。由于很多的功能都依赖于游戏日志,比如获取与服务端交互的命令结果,判断服务端的启动状态等等,它们在不断频繁地将日志全量加载到内存中后,必然会导致内存不足而OOM。

所以问题的根本原因就在于,游戏日志的读取加载的方法不正确。

解决

由于日志文件过大,所以不应该将其全量加载到内存中,在进行逐个分块读取过后,内存占用了有了较为明显的下降。

上次编辑于:
贡献者: yihhao wang