Go内存溢出与内存泄露

article/2025/9/17 11:14:22

https://www.cnblogs.com/sunsky303/p/11077030.html

一、内存泄露与内存溢出的区别

内存溢出(out of memory,简称OOM) 

内存溢出是指程序在申请内存时,没有足够的内存空间供其使用,简单点说就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出出现out of memory异常。

内存泄露(memory leak) 

内存泄露是指程序在申请内存后,无法释放已申请的内存空间,简单点说就是你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。

内存泄露指的是程序运行过程中已不再使用的内存,没有被释放掉,导致这些内存无法被使用,直到程序结束这些内存才被释放的问题。

Go虽然有GC来回收不再使用的堆内存,减轻了开发人员对内存的管理负担,但这并不意味着Go程序不再有内存泄露问题。

分配的内存不足以放下数据项序列,称为内存溢出

对于 C 和 C++ 这种没有 Garbage Collection 的语言来讲,我们主要关注两种类型的内存泄漏

1、堆内存泄漏(Heap leak)

        堆内存指的是程序运行中根据需要分配通过 malloc,realloc new 等从堆中分配的一块内存,再是完成后必须通过调用对应的 free 或者 delete 删掉。如果程序的设计的错误导致这部分内存没有被释放,那么此后这块内存将不会被使用,就会产生 Heap Leak。


2、系统资源泄露(Resource Leak)

        主要指程序使用系统分配的资源比如 Bitmap,handle ,SOCKET 等没有使用相应的函数释放掉,导致系统资源的浪费,严重可导致系统效能降低,系统运行不稳定。

不是所有的out of memory都是memory leak导致的,但是memory leak会最终会导致out of memory!

二、内存泄漏定位:

关于Go的内存泄露:10次内存泄露,有9次是goroutine泄露。

所以:掌握了如何定位和解决goroutine泄露,就掌握了Go内存泄露的大部分场景

2.1: pprof工具:

pprof是Go的性能分析工具,在程序运行过程中,可以记录程序的运行信息,可以是CPU使用情况、内存使用情况、goroutine运行情况等,当需要性能调优或者定位Bug时候,这些记录的信息是相当重要。

基本使用:

使用pprof有多种方式,Go已经现成封装好了1个:net/http/pprof,使用简单的几行命令,就可以开启pprof,记录运行信息,并且提供了Web服务,能够通过浏览器和命令行2种方式获取运行数据。

看个demo:

package mainimport ("fmt""net/http"_ "net/http/pprof"
)func main() {// 开启pprof,监听请求ip := "0.0.0.0:6060"if err := http.ListenAndServe(ip, nil); err != nil {fmt.Printf("start pprof failed on %s\n", ip)}

输入网址ip:port/debug/pprof/打开pprof主页,从上到下依次是5类profile信息

  1. block:goroutine的阻塞信息
  2. goroutine:所有goroutine的信息,下面的full goroutine stack dump是输出所有goroutine的调用栈,是goroutine的debug=2,后面会详细介绍。
  3. heap:堆内存的信息
  4. mutex:锁的信息
  5. threadcreate:线程信息

 

使用命令go tool pprof url可以获取指定的profile文件,此命令会发起http请求,然后下载数据到本地之后进入交互式模式,就像gdb一样,可以使用命令查看运行信息,以下是5类请求的方式:

# 下载cpu profile,默认从当前开始收集30s的cpu使用情况,需要等待30s
go tool pprof http://localhost:6060/debug/pprof/profile   # 30-second CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=120     # wait 120s# 下载heap profile
go tool pprof http://localhost:6060/debug/pprof/heap      # heap profile# 下载goroutine profile
go tool pprof http://localhost:6060/debug/pprof/goroutine # goroutine profile# 下载block profile
go tool pprof http://localhost:6060/debug/pprof/block     # goroutine blocking profile# 下载mutex profile
go tool pprof http://localhost:6060/debug/pprof/mutex

请求之后会展示以下信息: 

  1. 下载得到的文件:/home/ubuntu/pprof/pprof.demo.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz,这其中包含了程序名demo,profile类型alloc已分配的内存,inuse代表使用中的内存。
  2. help可以获取帮助,最先会列出支持的命令,想掌握pprof,要多看看,多尝试。关于命令,本文只会用到3个,我认为也是最常用的:toplisttraces,分别介绍一下。

  1. top:显示正运行到某个函数goroutine的数量
  2. traces:显示所有goroutine的调用栈
  3. list:列出代码详细的信息。

top会列出5个统计数据:

  • flat: 本函数占用的内存量。
  • flat%: 本函数内存占使用中内存总量的百分比。
  • sum%: 前面每一行flat百分比的和,比如第2行虽然的100% 是 100% + 0%。
  • cum: 是累计量,加入main函数调用了函数f,函数f占用的内存量,也会记进来。
  • cum%: 是累计量占总量的百分比。

怎么发现内存泄露

  1. 监控工具:固定周期对进程的内存占用情况进行采样,数据可视化后,根据内存占用走势(持续上升),很容易发现是否发生内存泄露。
  2. go pprof:适合没有监控工具的情况,使用Go提供的pprof工具判断是否发生内存泄露

总结

goroutine泄露的本质

goroutine泄露的本质是channel阻塞,无法继续向下执行,导致此goroutine关联的内存都无法释放,进一步造成内存泄露。

goroutine泄露的发现和定位

利用好go pprof获取goroutine profile文件,然后利用3个命令top、traces、list定位内存泄露的原因。

goroutine泄露的场景

泄露的场景不仅限于以下两类,但因channel相关的泄露是最多的。

  1. channel的读或者写:

    1. 无缓冲channel的阻塞通常是写操作因为没有读而阻塞
    2. 有缓冲的channel因为缓冲区满了,写操作阻塞
    3. 期待从channel读数据,结果没有goroutine写
  2. select操作,select里也是channel操作,如果所有case上的操作阻塞,goroutine也无法继续执行。

编码goroutine泄露的建议

为避免goroutine泄露造成内存泄露,启动goroutine前要思考清楚:

  1. goroutine如何退出?
  2. 是否会有阻塞造成无法退出?如果有,那么这个路径是否会创建大量的goroutine?


http://chatgpt.dhexx.cn/article/D9Rya08u.shtml

相关文章

(原创)攻击方式学习之(3) - 缓冲区溢出(Buffer Overflow)

堆栈溢出 堆栈溢出通常是所有的缓冲区溢出中最容易进行利用的。了解堆栈溢出之前,先了解以下几个概念: 缓冲区 简单说来是一块连续的计算机内存区域,可以保存相同数据类型的多个实例。堆栈 堆 栈是一个在计算机科学中经常使用的抽象数据类型。…

攻击方式学习之(3) - 缓冲区溢出(Buffer Overflow) [zt]

堆栈溢出 堆栈溢出通常是所有的缓冲区溢出中最容易进行利用的。了解堆栈溢出之前,先了解以下几个概念: 缓冲区 简单说来是一块连续的计算机内存区域,可以保存相同数据类型的多个实例。 堆栈 堆 栈是一个在计算机科学中经常使用的抽象数据类型…

linux 远程溢出,Linux Kernel蓝牙CAPI报文远程溢出漏洞

Linux Kernel是开放源码操作系统Linux所使用的内核。 Linux Kernel对入站CAPI消息没有执行正确的处理,远程攻击者可能利用此漏洞在服务器上执行任意指令。 Linux Kernel代码的net/bluetooth/cmtp/capi.c文件中没有正确地处理入站的CAPI消息。如果用户发送了特制的CA…

linux远程溢出,linux-ftpd-ssl 远程溢出漏洞

linux-ftpd-ssl 远程溢出漏洞 2005-11-15 eNet&Ciweek 详细描述: linux-ftpd-ssl是一款支持加密的FTP server。 linux-ftpd-ssl软件包中存在远程溢出漏洞,恶意服务器可能利用此漏洞在主机上执行任意指令。 恶意服务器生成的超长响应命令可能会覆盖栈…

html溢出攻击,溢出(漏洞)攻击的实现及防御

前言 媒体上关于系统漏洞的话题一直不断,在我所接触的用一些朋友和用户中虽然也知道打系统补丁很重要,但却又一直不以为然总以为网络上的危险离自己很远,大部份人都认为进行一次远程攻击很困难甚至认为只要安装了防病毒软件就一切大吉&#x…

缓冲区溢出(Buffer Overflow)

堆栈溢出 堆栈溢出通常是所有的缓冲区溢出中最容易进行利用的。了解堆栈溢出之前,先了解以下几个概念: 缓冲区 简单说来是一块连续的计算机内存区域,可以保存相同数据类型的多个实例。堆栈 堆 栈是一个在计算机科学中经常使用的抽象数据类型…

永恒之蓝漏洞复现(Windows server 2008系列缓冲区溢出漏洞)

漏洞信息 漏洞名称:Windows server 2008系列缓冲区溢出漏洞 CVEID:2017-0144 漏洞类型:输入验证错误 威胁类型:远程 发布时间:2017-03-14 危害等级:高危 漏洞简介 Microsoft服务器消息块1.0(…

攻击方式学习之(3) - 缓冲区溢出(Buffer Overflow)

堆栈溢出 堆栈溢出通常是所有的缓冲区溢出中最容易进行利用的。了解堆栈溢出之前,先了解以下几个概念: 缓冲区 简单说来是一块连续的计算机内存区域,可以保存相同数据类型的多个实例。堆栈 堆 栈是一个在计算机科学中经常使用的抽象数据类型…

缓冲区溢出实例(一)--Windows

一、基本概念 缓冲区溢出:当缓冲区边界限制不严格时,由于变量传入畸形数据或程序运行错误,导致缓冲区被填满从而覆盖了相邻内存区域的数据。可以修改内存数据,造成进程劫持,执行恶意代码,获取服务器控制权限等。 在Windows XP或2k3 server中的SLMail 5.5.0 Mail Server…

linux服务器接收缓冲区拥堵,Linux Kernel IP虚拟服务器栈缓冲区溢出漏洞

发布日期&#xff1a;2013-11-15 更新日期&#xff1a;2013-11-18 受影响系统&#xff1a; Linux kernel < 3.2.13 描述&#xff1a; -------------------------------------------------------------------------------- BUGTRAQ ID: 63744 CVE(CAN) ID: CVE-2013-4588 Li…

20155216 缓冲区溢出漏洞实验

20155216 缓冲区溢出漏洞实验 缓冲区溢出漏洞实验实验简介 缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况。这一漏洞可以被恶意用户利用来改变程序的流控制&#xff0c;甚至执行代码的任意片段。这一漏洞的出现是由于数据缓冲器和返回地址的暂时关闭&#x…

天骄辅助外挂制作,寻求合作

大家好&#xff0c; 进入正题现有我想开发一款游戏外挂&#xff0c;是针对新天娇的 不知您有没有开发外挂的经验呢&#xff1f;由于本人没有外挂开发的经验也暂时找不到相关的资料学习。 现在打算将这个项目外包出去&#xff0c; 要求&#xff1a; 一台机可以同时登录几个帐号 …

解剖一些外挂制作原理(DNF)

外挂现在大体上来讲分为三种&#xff0c;分别是模拟按键&#xff0c;WPE封包和内存挂。比如模拟键盘的&#xff0c;鼠标的&#xff0c;这种就叫做按键模拟&#xff0c;也叫脚本精灵&#xff1b;还有修改数据包的&#xff0c;这种就叫做WPE封包外挂&#xff0c;这种外挂相对而言…

外挂制作之思路总结和基址与偏移量

从今天起开始学习如何做外挂了 &#xff0c; 很久之前了解过一点皮毛。 无非是读写游戏进程中的内存数据。 再读写内存数据之前首先要做的就是找到游戏进程中在内存中的地址。在基地址中&#xff0c;利用CE寻找到某一数据对应的内存地址。计算出偏移量。然后每次都可以通过内存…

高中数学:数列求和的8种常用方法(最全)

高中数学&#xff1a;数列求和的8种常用方法&#xff08;电子版&#xff09;

常用数列求和公式

斐波那契数列 形如数列&#xff1a;1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ... 如果设F(n&#xff09;为该数列的第n项&#xff08;n∈N*&#xff09;&#xff0c;那么这句话可以写成如下形式: F(n)F(n-1)F(n-2) 通项公式: 求和公式: Sn2AnA(n-1) - 1 A(n2) -1 等…

在线等比数列求和计算器

在线等比数列求和计算器 在线等比数列求和计算器 该等比数列求和计算器可以计算指定等比数列各项之和,该等比数列求和计算器可以计算指定等比数列各项之和 https://tooltt.com/dbsl-sum/

蓝桥杯JAVA数列求和

import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in); int n sc.nextInt(); int a 1,b 1,c 1;for (int i 4; i < n; i) {int temp (a b c)%100000;//为了防止超过最大整数&#xff0c;可以…

C语言例程:数列求和

数列求和 计算 1121231234…12…n 的值。通过该实例&#xff0c;可以学习 if 条件判断语句和 for 循环语句的应用。程序运行结果如图 所示。 #include <stdio.h> int main() { int i,j,n; /* 定义循环变量 i,j&#xff0c;数列项数 n */ long int sum0,temp0; /* 定义…

C语言_等比数列求和

等比数列&#xff1a; 图片来源&#xff1a;百度百科 代码实现 1-递推求和 #include<stdio.h> int main() {int n, i;double q, sum, temp;while (scanf("%d %lf", &n, &q) ! EOF)//实现循环{sum 1;temp 1;for (i 0; i < n; i){temp * q;//让临…