不做大哥好多年 不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核

逍遥子

不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核
  • Python

  • GO

    • 01.GMP模型 ✅
    • 02.Map原理 ✅
    • 03.sync_map ✅
    • 04.sync.Pool
    • 05.垃圾回收 ✅
    • 06.channel
    • 07.内存逃逸
    • 08.内存泄漏
      • 01.内存泄漏概念
      • 02.内存泄漏排查
        • 1、排除掉goroutine泄漏
        • 2、确定是全局变量无回收
      • 03.goroutine 泄露的场景
        • 1、读写chan
        • 2、select所有case阻塞
        • 3、goroutine死循环
    • 09.mutex锁原理
    • 10.Go常识
    • 50.Golang常犯错误
    • 51.常见坑1~10
  • Java

  • 业务问题

  • 关键技术

  • 项目常识

  • 计算机基础

  • 常识
  • GO
xiaonaiqiang
2021-06-04
目录

08.内存泄漏

# 01.内存泄漏概念

  • 定义:由于疏忽或错误造成程序未能释放已经不再使用的内存

  • 情况1:僵尸进程

    • 有goroutine泄漏,goroutine“飞”了,zombie goroutine没有结束
    • 这个时候在这个goroutine上分配的内存对象将一直被这个僵尸goroutine引用着
    • 进而导致gc无法回收这类对象,内存泄漏
  • 情况2:全局数据结构挂住了本该释放的对象

    • 有一些全局(或者生命周期和程序本身运行周期一样长的)的数据结构意外的挂住了本该释放的对象
    • 虽然goroutine已经退出了,但是这些对象并没有从这类数据结构中删除,导致对象一直被引用,无法被回收

# 02.内存泄漏排查

# 1、排除掉goroutine泄漏

  • 首先,我利用压测工具对server进行100个websocket连接,模拟用户浏览行为,然后关闭连接
  • 打开浏览器查看goroutine数量,发现新起的goroutine全部已经销毁,没有观察到有泄漏的goroutine,因此排除此情况

# 2、确定是全局变量无回收

  • 再次用压测工具进行压测然后关闭,使用观察内存情况

  • 使用go tool pprof -inuse_space http://127.0.0.1:9999/debug/pprof/heap

  • 输入png导出(在这种情况下,需要等程序gc完再导出,建议等10分钟左右)

  • 发现问题所在

    • 每次都会遗留这么大概0.5M的内存空间出来
    • 就奇怪,明明整个goroutine退出为什么还有会内存占用?相应的全局变量也会删除该地方的引用
    • 等一下,全局变量,难道是删除的时候没做好配对导致没有真正删除该引用吗?
    • 去查了下代码,果然是没有删除引用导致的,至此问题解决

  • 这里面有个项目的坑,上报日志的key不是根据这个len(map)计算出,导致上报日志的时候以为删除了该key

# 03.goroutine 泄露的场景

  • goroutine泄露一般是因为channel操作阻塞而导致整个routine一直阻塞等待或者 goroutine 里有死循环的时候

  • 可以细分为下面五种情况

# 1、读写chan

  • 1)读取空无数据chan
  • 2)向满chan写入
  • leak 是一个有 bug 程序它启动了一个 goroutine 阻塞接收 channel
  • 当 Goroutine 正在等待时,leak 函数会结束返回
  • 此时,程序的其他任何部分都不能通过 channel 发送数据,那个 channel 永远不会关闭
  • fmt.Println 调用永远不会发生, 那个 goroutine 会被永远锁死
func leak() {
     ch := make(chan int)

     go func() {
        val := <-ch
        fmt.Println("We received a value:", val)
    }()
}
1
2
3
4
5
6
7
8

# 2、select所有case阻塞

  • 实现一个 fibonacci 数列生成器,并在独立的 goroutine 中运行
  • 在读取完需要长度的数列后,如果 用于 退出生成器的 quit 忘了被 close (或写入数据)
  • select 将一直被阻塞造成 该 goroutine 泄露
func fibonacci(c, quit chan int)  {
	x, y := 0, 1
	for{
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)

	go fibonacci(c, quit)

	for i := 0; i < 10; i++{
		fmt.Println(<- c)
	}

	// close(quit)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 3、goroutine死循环

// 粗暴的示例
func foo() {
  for{
    fmt.Println("fooo")
  }
}
1
2
3
4
5
6
上次更新: 2025/2/25 11:09:45
07.内存逃逸
09.mutex锁原理

← 07.内存逃逸 09.mutex锁原理→

最近更新
01
04.数组双指针排序_子数组
03-25
02
08.动态规划
03-25
03
06.回溯算法
03-25
更多文章>
Theme by Vdoing | Copyright © 2019-2025 逍遥子 技术博客 京ICP备2021005373号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式