1 回答

TA貢獻1784條經(jīng)驗 獲得超8個贊
pprof可以告訴你在哪里花費了內(nèi)存。只需為net/http/pprof包添加一個導(dǎo)入語句,并使用 http.DefaultServeMux 啟動一個 HTTP 服務(wù)器:
import _ "net/http/pprof"
func main() {
? ? go func() { log.Fatal(http.ListenAndServe(":4000", nil)) }()
? ? //...
}
在程序運行時,運行 pprof 工具來查看有關(guān)程序的各種統(tǒng)計信息。由于您關(guān)心內(nèi)存使用情況,因此堆配置文件(使用中的內(nèi)存)可能是最相關(guān)的。
$ go tool pprof -top 10 http://localhost:4000/debug/pprof/heap
Fetching profile over HTTP from http://localhost:4000/debug/pprof/heap
File: foo
Build ID: 10
Type: inuse_space
Time: Dec 21, 2018 at 12:52pm (CET)
Showing nodes accounting for 827.57MB, 99.62% of 830.73MB total
Dropped 9 nodes (cum <= 4.15MB)
? ? ? flat? flat%? ?sum%? ? ? ? cum? ?cum%
? 778.56MB 93.72% 93.72%? ?796.31MB 95.86%? time.NewTimer
? ?18.25MB? 2.20% 95.92%? ? 18.25MB? 2.20%? time.Sleep
? ?17.75MB? 2.14% 98.05%? ? 17.75MB? 2.14%? time.startTimer
? ? ? 11MB? 1.32% 99.38%? ? ? ?11MB? 1.32%? runtime.malg
? ? ? ?2MB? 0.24% 99.62%? ?798.31MB 96.10%? main.(*Session).readLoop
? ? ? ? ?0? ? ?0% 99.62%? ?798.31MB 96.10%? main.(*Session).Serve
? ? ? ? ?0? ? ?0% 99.62%? ? 18.25MB? 2.20%? main.(*Session).sendLoop
? ? ? ? ?0? ? ?0% 99.62%? ?800.81MB 96.40%? main.Loop
? ? ? ? ?0? ? ?0% 99.62%? ? 11.67MB? 1.40%? runtime.mstart
? ? ? ? ?0? ? ?0% 99.62%? ? 11.67MB? 1.40%? runtime.newproc.func1
? ? ? ? ?0? ? ?0% 99.62%? ? 11.67MB? 1.40%? runtime.newproc1
? ? ? ? ?0? ? ?0% 99.62%? ? 11.67MB? 1.40%? runtime.systemstack
? ? ? ? ?0? ? ?0% 99.62%? ?796.31MB 95.86%? time.After
time.Timer
不出所料,您創(chuàng)建的大量stime.After
占用了幾乎所有正在使用的內(nèi)存。
想一想:使用 250 毫秒的時間間隔,您創(chuàng)建計時器的速度比使用 1 秒的時間間隔快 4 倍。然而,計時器的壽命與間隔不成比例——它恒定為 60 秒。因此,在任何給定時間點,您有 4*60=240 倍以上的計時器處于活動狀態(tài)。
來自 time.After 的文檔:
等待持續(xù)時間過去后,然后在返回的通道上發(fā)送當(dāng)前時間。它等同于 NewTimer(d).C。在計時器觸發(fā)之前,垃圾收集器不會回收底層計時器。如果效率是一個問題,請改用 NewTimer 并在不再需要計時器時調(diào)用 Timer.Stop。
因此,為每個創(chuàng)建一個計時器readLoop
并重新使用它。您可以通過使用空結(jié)構(gòu)值通道而不是布爾值通道來進一步減少內(nèi)存使用:
type Session struct {
? ? KeepAlive chan struct{}
}
func (s *Session) readLoop() {
? ? fmt.Println("readLoop")
? ? d := 1 * time.Minute
? ? t := time.NewTimer(d)
loop:
? ? for {
? ? ? ? select {
? ? ? ? case _, ok := <-s.KeepAlive:
? ? ? ? ? ? if !ok {
? ? ? ? ? ? ? ? break loop
? ? ? ? ? ? }
? ? ? ? ? ? if !t.Stop() {
? ? ? ? ? ? ? ? <-t.C
? ? ? ? ? ? }
? ? ? ? ? ? t.Reset(d)
? ? ? ? case <-t.C:
? ? ? ? ? ? fmt.Println("Timeout")
? ? ? ? ? ? break loop
? ? ? ? }
? ? }
? ? fmt.Println("readLoop EXIT")
}
func (s *Session) sendLoop() {
? ? defer close(s.KeepAlive)
? ? for {
? ? ? ? s.KeepAlive <- struct{}{}
? ? ? ? time.Sleep(interval)
? ? }
}
- 1 回答
- 0 關(guān)注
- 147 瀏覽
添加回答
舉報