goroutine泄露:原理、场景、检测和防范

本文详细介绍了Go语言中goroutine泄露的五个常见场景,包括channel操作不当、死循环等,并提供了检测和定位泄露的方法,如使用监控工具和pprof。防范goroutine泄露的关键在于合理设计goroutine的结束机制、避免channel阻塞及确保正确实现循环退出条件。
摘要由CSDN通过智能技术生成

如果你启动了一个 goroutine,但并没有符合预期的退出,直到程序结束,此goroutine才退出,这种情况就是 goroutine 泄露。当 goroutine 泄露发生时,该 goroutine 的栈(一般 2k 内存空间起)一直被占用不能释放,goroutine 里的函数在堆上申请的空间也不能被 垃圾回收器 回收。这样,在程序运行期间,内存占用持续升高,可用内存越来也少,最终将导致系统崩溃。

回顾一下 goroutine 终止的场景:

  • 当一个goroutine完成它的工作
  • 由于发生了没有处理的错误
  • 有其他的协程告诉它终止

那么当这三者同时没发生的时候,就会导致 goroutine 始终不会终止退出。

goroutine 泄露的场景

goroutine泄露一般是因为channel操作阻塞而导致整个routine一直阻塞等待或者 goroutine 里有死循环的时候。可以细分为下面五种情况:

1. 从 channel 里读,但是没有写
// 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)
    }()
}
2. 向 unbuffered channel 写,但是没有读
// 一个复杂一点的例子
func sendMsg(msg, addr string) error {
   
    conn, err := net.Dial("tcp", addr)
    if err != nil {
   
        return err
    }
    defer conn.Close()
    _, err = fmt.Fprint(conn, msg)
    return err
} 

func broadcastMsg(msg string, addrs []string) error {
   
    errc := make
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值