问题
项目中遇到的一个问题,项目运行一段时间后CPU使用率会逐步上升到100%,导致系统异常,排查是在Ticker上使用出现错误,网上也有类似的案例:在使用Tikcer后没有释放导致。在此做下记录。
引用一段代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| func (p *Pinger) run() { timeout := time.NewTicker(p.Timeout) interval := time.NewTicker(p.Interval) for { select { case <-p.done: wg.Wait() return case <-timeout.C: close(p.done) wg.Wait() return case <-interval.C: if p.Count > 0 && p.PacketsSent >= p.Count { continue } err = p.sendICMP(conn) if err != nil { fmt.Println("FATAL: ", err.Error()) } case r := <-recv: err := p.processPacket(r) if err != nil { fmt.Println("FATAL: ", err.Error()) } } if p.Count > 0 && p.PacketsRecv >= p.Count { close(p.done) wg.Wait() return } } }
|
该段代码可以看出,这个函数是有出口的,但在出口处没有关闭Ticker,导致资源泄露。这个问题已经被修复了,可以看到修复后的局部代码如下:
1 2 3 4
| timeout := time.NewTicker(p.Timeout) defer timeout.Stop() interval := time.NewTicker(p.Interval) defer interval.Stop()
|
总结
有一种情况使用Ticker不主动关闭也不会造成资源泄露,比如,函数创建Ticker后就不会退出,直到进程结束。这种情况下不会持续的创建Ticker,也就不会造成资源泄露。
但是,不管哪种情况,创建一个Ticker后,紧跟着使用defer语句关闭Ticker总是好的习惯。因为,有可能别人无意间拷贝了你的部分代码,而忽略了关闭Ticker的动作。