Goroutine泄露的概念及常见原因汇总

前言

在一次面试中被问到这个问题,当时不是特别了解。后续学习协程池时候也遇到了这个概念(协程池的优势),因此特来学习一下。
在这里插入图片描述

定义

Go的并发是以goroutine和channel的形式实现的。协程泄露是指goroutine创建后,由于一些错误,长时间得不到释放。继续不断创建新的goroutine协程,最终导致内存耗尽,程序崩溃。

简单来说,协程泄露就是指创建的goroutine炸了导致无法释放,所以一直卡的占内存,长期以往让整个系统直接挂掉。

常见情况

通道chan相关

1、发送不接收
2、接收不发送
3、没有初始化

chan本身的一些操作,会导致阻塞。
比如对于一个无缓存通道的发送操作,必须等到有地方接收,才会正常进行下去,否则就会一直阻塞。接收必须等到有发送,否则也会阻塞。
同理,如果对于有缓存通道已满的情况的发送,或者为空情况的接收也是如此。
因此如果接收不发送或者发送不接收,都会带来阻塞的问题。
其次,如果chan忘记初始化,这里的chan则是nil,所以也会一直阻塞。(相关测试见此文)

无限死循环

1、I/O操作的阻塞
2、逻辑上的死循环
对于逻辑死循环,好理解,就是单纯写错代码死循环了,所以导致此goroutine无法结束。

对于I/O操作阻塞,常见的是如发送HTTP请求至服务器没有使用超时。
直接引用煎鱼这篇文章中的测试用例。

func main() {
    for {
        go func() {
            _, err := http.Get("https://www.xxx.com/")
            if err != nil {
                fmt.Printf("http.Get err: %v\n", err)
            }
            // do something...
    }()

    time.Sleep(time.Second * 1)
    fmt.Println("goroutines: ", runtime.NumGoroutine())
    }
}

这种在协程中去请求,因为网络等原因造成超时响应,自然会一直卡住。
因此需要记得手动设置一下超时时间。

    httpClient := http.Client{
        Timeout: time.Second * 15,
    }

死锁

此部分代码来自煎鱼

1、互斥锁没解锁
2、同步锁用错了

实际情况来看,第一个就是单纯加了锁忘记解,第二种就是用完wg.add(1),忘记了wg.done,导致持续wait()。因此解决方法是加了记得解,go中使用defer是多么方便的一件事情…

 var mutex sync.Mutex
    for i := 0; i < 10; i++ {
        go func() {
            mutex.Lock()
            defer mutex.Unlock()
            total += 1
    }()
    }
  var wg sync.WaitGroup
    for i := 0; i < v; i++ {
        wg.Add(1)
        defer wg.Done()
        fmt.Println("脑子进煎鱼了")
    }
    wg.Wait()

Select阻塞

select会在所有case中随机选择一个满足的去执行,如果所有均不满足,则会执行default中的命令。如果没有加default的话,则会持续阻塞,直到任意一个满足再去执行。

因此如果没有设置default,且一直无法满足,则会长时间阻塞。

排查

网络上普遍使用 pprof进行检测。因为目前没有实战遇到,所以仅仅是理论学习为主,埋下坑了解为先。
相关资源:

https://www.cnblogs.com/xiaowangba/p/6313755.html

https://cloud.tencent.com/developer/article/2291519

总结

Goroutine泄露是Golang中常见的一种错误,网上有话说“Go 10次内存泄漏,8次goroutine泄漏,1次是真正内存泄漏,还有1次是cgo导致的内存泄漏”。因此一定不可掉以轻心。

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值