社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
默认的time.After()是会有内存泄漏问题的,因为每次time.After(duratiuon x)会产生NewTimer(), 在duration x到期之前, 新创建的timer不会被GC,到期之后才会GC
那么随着时间推移,尤其是duration x很大的话,会产生内存泄漏的问题。
import (
"fmt"
"net/http"
_ "net/http/pprof"
"time"
)
func Ticker() {
ch := make(chan string, 100)
go func() {
for {
ch <- "y"
}
}()
go func() {
if err := http.ListenAndServe("127.0.0.1:9999", nil); err != nil {
fmt.Println("http server fail")
}
}()
for {
select {
case <-ch:
case <-time.After(time.Minute * 3):
}
}
}
go tool pprof -http=:8081 http://localhost:9999/debug/pprof/heap```
可以看出大量调用time.NewTicker()导致的内存泄漏问题
不用time.After()
而用time.Ticker()
func RightTicker() {
ch := make(chan string, 100)
go func() {
for {
ch <- "y"
}
}()
go func() {
if err := http.ListenAndServe("127.0.0.1:9999", nil); err != nil {
fmt.Println("http server fail")
}
}()
tk := time.NewTimer(time.Minute * 3)
for {
select {
case <-ch:
if !tk.Stop() {
<-tk.C
}
case <-tk.C:
}
tk.Reset(time.Minute * 3)
}
tk.Stop()
}
// Reset changes the timer to expire after duration d.
// It returns true if the timer had been active, false if the timer had
// expired or been stopped.
//
// For a Timer created with NewTimer, Reset should be invoked only on
// stopped or expired timers with drained channels.
//
// If a program has already received a value from t.C, the timer is known
// to have expired and the channel drained, so t.Reset can be used directly.
// If a program has not yet received a value from t.C, however,
// the timer must be stopped and—if Stop reports that the timer expired
// before being stopped—the channel explicitly drained:
//
// if !t.Stop() {
// <-t.C
// }
// t.Reset(d)
//
// This should not be done concurrent to other receives from the Timer's
// channel.
//
// Note that it is not possible to use Reset's return value correctly, as there
// is a race condition between draining the channel and the new timer expiring.
// Reset should always be invoked on stopped or expired channels, as described above.
// The return value exists to preserve compatibility with existing programs.
//
// For a Timer created with AfterFunc(d, f), Reset either reschedules
// when f will run, in which case Reset returns true, or schedules f
// to run again, in which case it returns false.
// When Reset returns false, Reset neither waits for the prior f to
// complete before returning nor does it guarantee that the subsequent
// goroutine running f does not run concurrently with the prior
// one. If the caller needs to know whether the prior execution of
// f is completed, it must coordinate with f explicitly.
func (t *Timer) Reset(d Duration) bool {
if t.r.f == nil {
panic("time: Reset called on uninitialized Timer")
}
w := when(d)
return resetTimer(&t.r, w)
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!