Golang --time-After-- 在計時器過期前不會被垃圾回收
最近我在調查 Go 應用程序中內存泄漏的問題,這個問題主要因爲我沒有正確的閱讀文檔。這是一段導致消耗了多個 Gbs 內存的代碼:
func ProcessChannelMessages(ctx context.Context, in <-chan string, idleCounter prometheus.Counter) {
for {
start := time.Now()
select {
case s, ok := <-in:
if !ok {
return
}
// handle `s`
case <-time.After(5 * time.Minute):
idleCounter.Inc()
case <-ctx.Done():
return
}
}
}
以下是應用程序的內存指標圖:
在圖中左側,可以看到修復之前的內存消耗,右側是修改後的內存消耗。分析器顯示 <-time.After 是內存泄漏的原因。直到我讀到以下文檔時,我才感到驚訝:
在計時器觸發之前,垃圾收集器不會回收 Timer。
所以 9Gb 的內存被定期垃圾回收變得非常必要了。我們在 channel 中每秒有 60k 個消息,在每個給定時刻分配大約 1800 萬個計時器加上一些不確定數字的計時器等待被垃圾回收。
func ProcessChannelMessages(ctx context.Context, in <-chan string, idleCounter prometheus.Counter) {
idleDuration := 5 * time.Minute
idleDelay := time.NewTimer(idleDuration)
defer idleDelay.Stop()
for {
idleDelay.Reset(idleDuration)
select {
case s, ok := <-in:
if !ok {
return
}
// handle `s`
case <-idleDelay.C:
idleCounter.Inc()
case <-ctx.Done():
return
}
}
}
微不足道的重構有助於將內存消耗減少 20 倍,這些都是閱讀文檔就能解決的問題。
via: https://medium.com/@oboturov/golang-time-after-is-not-garbage-collected-4cbc94740082
作者:Artem OBOTUROV[1] 譯者:咔嘰咔嘰 [2] 校對:polaris1119[3]
本文由 GCTT[4] 原創編譯,Go 中文網 [5] 榮譽推出,發佈在 Go 語言中文網公衆號,轉載請聯繫我們授權。
參考資料
[1]
Artem OBOTUROV: https://medium.com/@oboturov
[2]
咔嘰咔嘰: https://github.com/watermelo
[3]
polaris1119: https://github.com/polaris1119
[4]
GCTT: https://github.com/studygolang/GCTT
[5]
Go 中文網: https://studygolang.com/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/HtvJMGWmGnToplaz54pUaw