Golang处理内存溢出方式

 更新时间:2024年12月20日 10:08:33   作者:dkjhl  
本文介绍了Golang中分析内存溢出问题的三种工具:pprof、GoMemstats和程序crash时自动创建dump文件,通过这些工具,可以对程序的内存使用情况进行详细分析,从而找出内存溢出的原因

背景

最近系统在压测过程中发现主程序在并发增大后会出现主程序闪退现象,几经波折,认为有可能是内存溢出引起的

正好对 Golang 里分析 dump 这块还没怎么涉及,借此契机研究一下。

前言

查看社区后,发现在Golang中,发生内存溢出通常会导致程序直接崩溃退出,而无法像其他语言一样生成core dump文件。

因此,Golang社区提供了一些工具可以帮助用户进行内存分析。

以下是两个常用的工具:

1. pprof

pprof是Golang内置的性能分析工具,在分析内存使用方面非常有用。

通过设置一个标志位并在程序退出时打开pprof服务器,程序可以向pprof服务器报告一些性能数据,例如内存使用情况。

可以在代码中加入以下代码,启动pprof服务器并在本地8080端口进行访问:

import "net/http"
import _ "net/http/pprof"

func main() {
    go func() {
        http.ListenAndServe("localhost:8080", nil)
    }()
    // ...
}

启动pprof服务器之后,可以访问http://localhost:8080/debug/pprof/heap进行堆内存分析,获取内存占用的堆快照。

上图中框出的这 4 个部分应该是平时最常用的,从上往下分别是:

  • 阻塞分析: 比如,goroutine 的 wait。
  • 内存分析: 比如,内存泄漏、内存消耗异常等情况。
  • 互斥锁分析: 比如,观察代码里用到的sync.RWMutex 和 sync.Mutex 的具体情况。
  • CPU 分析: 比如,排查哪些代码较多地占用了 CPU 资源。

以下是一段消耗内存的代码,用于走读流程,如下:

func main() {
	go func() { http.ListenAndServe("0.0.0.0:8899", nil) }()
	str := "gejigejigejigejigejigejigejigjeijgiewjiasdiahdkuhakudsfhakdshgkjasdkjgbakjsdfioajewoiepqbibgijqbgoipbjwebkjfqjkw egqhwejbgfaijwebgjqhb"
	for i := 0; i < 999; i++ {
		str += str
	}
	fmt.Scanln()
}

在 web 页面点击「heap」入口,我们可以看到实时内存的使用情况。

再通过以下命令进入到命令交互模式看看效果:

go tool pprof http://localhost:8899/debug/pprof/heap

进去之后输入「top」,就能很直观的看到哪个方法占用了内存。

这里的几个列的含义简单罗列下:

  • flat:当前函数所占用的容量。
  • flat%:当前函数所占用的容量,在总分配容量的百分比。
  • sum%:是从调用的最外层到当前方法累加使用的容量占总容量的百分比
  • cum:当前函数以及子函数所占用的容量。
  • cum%:当前函数以及子函数所占用的容量,在总分配容量的百分比。
  • 最后一列是函数的名字

可以再输入获得更详细的信息:

list main.main

上述指令会罗列出每行代码占用的容量;其他类似,如下是分析CPU的

2. Go Memstats

Go Memstats是一个Golang的标准库工具,用于收集和显示内存信息。

可以在代码中导入“runtime”包,并调用“runtime.ReadMemStats(&mem)”函数收集内存信息。

然后可以打印内存使用情况的详情,例如总分配量和分配的堆块数量等。

以下是示例代码:

import (
    "fmt"
    "runtime"
)

func main() {
    var mem runtime.MemStats
    runtime.ReadMemStats(&mem)
    fmt.Printf("TotalAlloc (Heap) = %v MiB\n", mem.TotalAlloc/mb)
    fmt.Printf("Alloc = %v MiB\n", mem.Alloc/mb)
    fmt.Printf("Sys = %v MiB\n", mem.Sys/mb)
    fmt.Printf("NumGC = %v\n", mem.NumGC)
}

这将输出程序中已分配的总内存,已使用的内存量,系统内存使用情况和垃圾回收次数等信息。

使用这些信息,可以分析内存占用量的增长和优化内存使用。

3. 程序 crash 的时候自动创建 dump 文件

大多数时候,我们可能没有条件实时分析程序运行情况。

比如问题在生产环境偶发出现,且无法在测试环境重现。

这个时候我们可以配置当程序 crash 的时候自动保存 dump 文件。

先输入命令「ulimit -a」看下当前是否开启了core file。

这里的数字单位是 block,具体需要根据所在的操作系统一个 block 对应的大小来设置。如果是0的话说明未开启。可以通过:

ulimit -c 1024 或者 ulimit -c unlimited 来设置 dump 文件的最大 size。

如果想要永久有效,则:

echo "ulimit -c unlimited" >> ~/.profile

让程序发生 crash 的时候会自动生成 dump 文件

## 临时有效
export GOBACTRACE=crash

## 永久有效
echo "export GOTRACEBACK=crash " >> ~/.profile

这就意味着,让程序发生 crash 的时候会自动生成 dump 文件。

有了 dump 文件,可以用 gdb 或者 delve 工具来分析了(官方更建议我们使用 delve,对 Golang 的支持更好)

总之啊,无论你使用哪种工具,分析Golang内存溢出问题需要耐心和技巧。

建议不仅可以使用这些工具进行数据分析,同时还应该阅读关于垃圾回收机制和内存管理的文档,尝试实现更好的编码习惯,以减少内存溢出的可能性。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 基于Go语言实现简单的计算器

    基于Go语言实现简单的计算器

    这篇文章主要为大家详细介绍了如何基于Go语言实现简单的计算器,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-10-10
  • golang flag介绍和使用示例

    golang flag介绍和使用示例

    本文主要介绍了Go语言中flag包的使用方法,详细阐述了基本概念及常用函数,并通过示例代码进行了具体演示,总结中指出,flag包提供了一种方便的方式来处理命令行参数,可定义不同类型的标志,并在解析后使用这些参数
    2024-10-10
  • Golang实现CronJob(定时任务)的方法详解

    Golang实现CronJob(定时任务)的方法详解

    这篇文章主要为大家详细介绍了Golang如何通过一个单 pod 去实现一个常驻服务,去跑定时任务(CronJob),文中的示例代码讲解详细,需要的可以参考下
    2023-04-04
  • Golang极简入门教程(四):编写第一个项目

    Golang极简入门教程(四):编写第一个项目

    这篇文章主要介绍了Golang极简入门教程(四):编写第一个项目,本文讲解了workspace、包路径、第一个可执行命令等内容,需要的朋友可以参考下
    2014-10-10
  • Go实现自动解压缩包以及读取docx/doc文件内容详解

    Go实现自动解压缩包以及读取docx/doc文件内容详解

    在开发过程中,我们常常需要处理压缩包和文档文件。本文将介绍如何使用Go语言自动解压缩包和读取docx/doc文件,需要的可以参考一下
    2023-03-03
  • Go语言实现自动填写古诗词实例代码

    Go语言实现自动填写古诗词实例代码

    这篇文章主要给大家介绍了关于Go语言实现自动填写古诗词的相关资料,这是最近在项目中遇到的一个需求,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2018-03-03
  • Go 语言sort 中的sortInts 方法

    Go 语言sort 中的sortInts 方法

    这篇文章主要介绍了Go 语言sort 中的sortInts 方法,Go 的 sort 包实现了内置和用户定义类型的排序。我们将首先查看内置函数的排序,西瓦嗯更多相关资料需要的小伙伴可以参考一下
    2022-04-04
  • golang 四则运算计算器yacc归约手写实现

    golang 四则运算计算器yacc归约手写实现

    这篇文章主要为大家介绍了golang 四则运算 计算器 yacc 归约的手写实现,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 详解go如何使用xorm在执行前改写 SQL

    详解go如何使用xorm在执行前改写 SQL

    这篇文章主要为大家介绍了详解go如何使用xorm在执行前改写SQL的实现过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • golang下的GOPATH路径问题及解决

    golang下的GOPATH路径问题及解决

    为了方便,我一般使用task来管理项目的编译等事项,由于才入门go,所以碰到一个问题,以此篇为记,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01

最新评论