【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
}
}
}