Go語言bytes.makeSlice導致內存泄漏:如何避免服務器端大內存占用?

Go語言bytes.makeSlice導致內存泄漏:如何避免服務器端大內存占用?

go語言bytes.makeSlice與內存泄漏:剖析及解決方案

高效的內存管理對于Go語言程序至關重要。本文將分析一個案例,探討bytes.makeSlice函數與內存泄漏的關聯(lián),并提供有效的解決方案。

問題描述:一個基于Fiber框架的Go http服務器,其/test路由生成一個包含百萬個”123″字符串的大型字節(jié)緩沖區(qū)并返回給客戶端。當客戶端并發(fā)發(fā)起大量請求時,go tool pprof分析顯示bytes.makeSlice占據大量內存,且程序結束后內存未能完全釋放。

服務器端代碼(示例):

立即學習go語言免費學習筆記(深入)”;

package main  import (     "bytes"      "github.com/gofiber/fiber/v2"     "github.com/gofiber/fiber/v2/middleware/pprof" )  func main() {     app := fiber.New()     app.Use(pprof.New())     app.Get("/test", func(c *fiber.Ctx) error {         buffer := bytes.NewBufferString("")         for i := 0; i < 1000000; i++ {             buffer.WriteString("123")         }         return c.SendString(buffer.String())     })     app.Listen(":3000") }

客戶端代碼(示例):

package main  import (     "fmt"     "io"     "net/http"     "sync" )  func main() {     var wg sync.WaitGroup     for i := 0; i < 500; i++ {         wg.Add(1)         go func() {             defer wg.Done()             resp, err := http.Get("http://localhost:3000/test")             if err != nil {                 fmt.Println("Error:", err)                 return             }             defer resp.Body.Close() //關鍵:關閉響應體             io.Copy(io.Discard, resp.Body)         }()     }     wg.Wait() }

go tool pprof分析結果表明bytes.makeSlice占據大量內存。根本原因在于:服務器端每次請求都創(chuàng)建大型字節(jié)緩沖區(qū),而客戶端未正確關閉響應體(resp.Body.Close()),導致服務器端分配的內存無法被垃圾回收。

問題根源:客戶端代碼缺少resp.Body.Close()。resp.Body是io.ReadCloser,使用完畢后必須調用Close()釋放底層資源,從而允許服務器釋放相關內存。 忽略Close()會導致內存泄漏,即使bytes.makeSlice本身沒有問題。

解決方案:在客戶端代碼中,確保在讀取完響應體后調用resp.Body.Close(),正確釋放資源,避免內存泄漏。 改進后的客戶端代碼如上所示,包含了defer resp.Body.Close()。 這行代碼確保在函數返回前,無論是否發(fā)生錯誤,響應體都被正確關閉。

以上就是Go語言bytes.makeSlice導致內存泄漏:如何避免服務器端大

? 版權聲明
THE END
喜歡就支持一下吧
點贊8 分享