【go】time.after内存泄漏

func worker() {
  select {
  case <-c:
       // ... do some stuff
  case <-time.After(30 *time.Second):
      return
  }
}

它创建了一个计时器,但返回的只是计时器关联的通道
如果不从返回的通道中接收值,即使超时发生后,计时器也不会被垃圾回收
这会导致计时器泄漏,特别是在循环中使用时会创建大量无法及时回收的计时器

改进方法 调用defer 进行stop

func worker() {
  timer := time.NewTimer(30 * time.Second)
  defer timer.Stop() // 确保定时器被清理
select {
  case <-c:
       // ... do some stuff
  case <-timer.C:
      return
  }
}

Kubernetes中的改进方式: 重用定时器

在maxinflight.go的代码中,使用了wait.Until函数,其内部已经正确处理了定时器的创建和清理:
(接上篇 maxinflight.go 的源码略读)


func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
    JitterUntil(f, period, 0.0, true, stopCh)
}
func JitterUntil(f func(), period time.Duration, jitterFactor float64, sliding bool, stopCh <-chan struct{}) {
    var t *time.Timer
    var sawTimeout bool
	for {
    select {
    case <-stopCh:
        return
    default:
    }

    jitteredPeriod := period
    if jitterFactor > 0.0 {
        jitteredPeriod = Jitter(period, jitterFactor)
    }

    if !sliding {
        t = resetOrReuseTimer(t, jitteredPeriod, sawTimeout)
    }

    func() {
        f()
    }()

    if sliding {
        t = resetOrReuseTimer(t, jitteredPeriod, sawTimeout)
    }

    // 注意这里重用了定时器
    select {
    case <-stopCh:
        return
    case <-t.C:
        sawTimeout = true
    }
}
}

你可能感兴趣的:(golang)