zoukankan      html  css  js  c++  java
  • 【涨姿势】原来golang的case <-time.After(xxx)还有这样的坑

    偶然看到这样一篇文章:《使用 pprof 排查 Golang 内存泄露》https://www.toutiao.com/i6881796351139676680/
    最后一段让我很疑惑:

    修改 for ... select ... time.After 造成的内存泄露
    原来程序中存在如下代码:
    
    for {
    		select {
    		case a := <-chanA:
    			...		case b := <-chanB:
    			....		case <-time.After(20*time.Minutes):
    			return nil, errors.New("download timeout")
    	} 
    time.After 就是封装了一层的 NewTimer, time.After 的源码:
    
    func After(d Duration) <-chan Time {
    	return NewTimer(d).C
    }
    修复该错误, 只调用一次 NewTimer:
    
    downloadTimeout := time.NewTimer(20 * time.Minute)
    defer downloadTimeout.Stop()
    for {
    		select {
    		case a := <-chanA:
    			...		case b := <-chanB:
    			....		case <-downloadTimeout.C:
    			return nil, errors.New("download timeout")
    	} 
    

    连官网的例子都是:case <-time.After(xxx), 为什么这里就出现内存泄露了?
    感谢yifhao同学耐心细致的讲解:

    • 20 * time.Minute 这个时间太长了
    • 如果1s钟调用这里1000次, 那就可能会同时存在20601000个定时事件
    • 退出select的作用域的时候,time.After(20*time.Minutes)产生的对象不会被GC,走到runtime里的timer调度去了
    • 退出作用域不会被释放. 定时事件作用域在timer的调度器上去了。定时器是全局对象. 调度到了才被释放。
    • 因此,时间短,且循环不频繁的情况下,case <-time.After(xxx)这个写法还是可以的
  • 相关阅读:
    python
    python
    python
    python
    python 序列化
    字典
    异常处理
    类的成员,类的特殊方法
    HTMLEditor类常用方法说明
    HTMLEditor类常用属性说明
  • 原文地址:https://www.cnblogs.com/ahfuzhang/p/13805561.html
Copyright © 2011-2022 走看看