欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang使用pprof檢查內(nèi)存泄漏的全過(guò)程

 更新時(shí)間:2024年02月04日 09:35:33   作者:hankeyyh  
pprof 是golang提供的一款分析工具,可以分析CPU,內(nèi)存的使用情況,本篇文章關(guān)注它在分析內(nèi)存泄漏方面的應(yīng)用,本文給大家介紹了Golang使用pprof檢查內(nèi)存泄漏的全過(guò)程,文中通過(guò)代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下

前言

pprof 是golang提供的一款分析工具,可以分析CPU,內(nèi)存的使用情況,本篇文章關(guān)注它在分析內(nèi)存泄漏方面的應(yīng)用。pprof 不能直觀顯示出某個(gè)函數(shù)發(fā)生了泄漏,它的用途是列出當(dāng)前內(nèi)存分配較大的位置,通過(guò)比較一段時(shí)間pprof的結(jié)果,可以發(fā)現(xiàn)內(nèi)存變化。

測(cè)試代碼

比如我們有下面的函數(shù),在請(qǐng)求中對(duì)全局變量分配了一塊內(nèi)存,但沒(méi)有回收:

package main

import (
    "fmt"
    "log"
    "net/http"
    _ "net/http/pprof" // 關(guān)鍵??!
    "runtime"
    "sync"
)

type UserData struct {
    Data []byte
}

type UserCache struct {
    mu    sync.Mutex
    Cache map[string]*UserData
}

func (uc *UserCache) clear() {
    uc.mu.Lock()
    defer uc.mu.Unlock()
    uc.Cache = make(map[string]*UserData)
}

func NewUserCache() *UserCache {
    return &UserCache{
        Cache: make(map[string]*UserData),
    }
}

var userCache = NewUserCache()

// 分配全局內(nèi)存
func handleRequest(w http.ResponseWriter, r *http.Request) {
    userCache.mu.Lock()
    defer userCache.mu.Unlock()
    
    userData := &UserData{
        Data: make([]byte, 1000000),
    }

    userID := fmt.Sprintf("%d", len(userCache.Cache))
    // 賦值給全局變量,但沒(méi)有回收
    userCache.Cache[userID] = userData
    log.Printf("Added data for user %s. Total users: %d\n", userID, len(userCache.Cache))
}

// 清空全局內(nèi)存
func handleClear(w http.ResponseWriter, r *http.Request) {
    userCache.clear()
    runtime.GC()
}

func main() {
    http.HandleFunc("/leaky-endpoint", handleRequest)
    http.HandleFunc("/clear", handleClear)
    
    http.ListenAndServe(":8080", nil)
}

其中 import "net/http/pprof" 引入了pprof工具,啟動(dòng)服務(wù)后,內(nèi)存分析結(jié)果保存在http://localhost:8080/debug/pprof/heap。

發(fā)送請(qǐng)求

我們往/leaky-endpoint發(fā)送一些請(qǐng)求,觸發(fā)全局內(nèi)存分配,可以使用 ab 命令:

ab -n 1000 -c 10 http://localhost:8080/leaky-endpoint

-n:請(qǐng)求數(shù)量,我們總共發(fā)送1000個(gè)請(qǐng)求

-c:并發(fā)數(shù)量,1000個(gè)請(qǐng)求通過(guò)10個(gè)并發(fā)線程發(fā)送

分析內(nèi)存

查看內(nèi)存分配

我們可以通過(guò)下面的命令查看分析結(jié)果:

pprof http://localhost:8080/debug/pprof/heap

// output: 
// Entering interactive mode (type "help" for commands, "o" for options)
// (pprof)

輸入上述命令后,會(huì)進(jìn)入命令行交互模式,我們可以輸入一系列幫助命令查看內(nèi)存分析結(jié)果:

  • top:輸出內(nèi)存分配最多的幾個(gè)函數(shù)
(pprof) top
Showing nodes accounting for 487.41MB, 100% of 487.41MB total
      flat  flat%   sum%        cum   cum%
  487.41MB   100%   100%   487.41MB   100%  main.handleRequest
         0     0%   100%   487.41MB   100%  net/http.(*ServeMux).ServeHTTP
         0     0%   100%   487.41MB   100%  net/http.(*conn).serve
         0     0%   100%   487.41MB   100%  net/http.HandlerFunc.ServeHTTP
         0     0%   100%   487.41MB   100%  net/http.serverHandler.ServeHTTP

可以看到,handleRequest 分配了最多的內(nèi)存。這幾列的含義是:

  • flat:函數(shù)自身在采樣期間直接消耗的內(nèi)存,不包括它調(diào)用的其他函數(shù)的消耗;
  • flag%: flat 值占總消耗資源的百分比,這個(gè)百分比是基于整個(gè)程序在采樣期間的資源消耗來(lái)計(jì)算的;
  • sum%: 累積百分比,表示從輸出列表頂部開(kāi)始到當(dāng)前行為止的所有函數(shù)的 flat 百分比之和。這可以幫助你理解最頂部的函數(shù)累積起來(lái)消耗了多少資源;
  • cum: 函數(shù)自身flat,加上它調(diào)用的所有函數(shù)在采樣期間消耗的內(nèi)存;
  • cum%: cum 值占總消耗資源的百分比。這個(gè)百分比顯示了函數(shù)及其所有遞歸調(diào)用的資源消耗在程序總資源消耗中的比重;
  • list:列出函數(shù)具體分配內(nèi)存的位置
(pprof) list main.handleRequest
Total: 487.41MB
ROUTINE ======================== main.handleRequest in /home/yuhanyang/project/HelloGo/test_mem_leak/main.go
 487.41MB   487.41MB (flat, cum)   100% of Total
        .          .     35:func handleRequest(w http.ResponseWriter, r *http.Request) {
        .          .     36:   userCache.mu.Lock()
        .          .     37:   defer userCache.mu.Unlock()
        .          .     38:
        .          .     39:   userData := &UserData{
 487.41MB   487.41MB     40:           Data: make([]byte, 1000000),
        .          .     41:   }
  • web:在瀏覽器中生成并打開(kāi) SVG 格式的調(diào)用圖

  • png:生成 PNG 格式的調(diào)用圖

比較內(nèi)存分配

為了分析內(nèi)存泄漏,我們往往需要統(tǒng)計(jì)一段時(shí)間開(kāi)始和結(jié)束時(shí)的內(nèi)存變化情況,在上面的基礎(chǔ)上,我們可以再用ab命令觸發(fā)幾次內(nèi)存分配,然后通過(guò)pprof查看:

>>pprof  http://localhost:8080/debug/pprof/heap
(pprof) top
Showing nodes accounting for 3.74GB, 100% of 3.74GB total
      flat  flat%   sum%        cum   cum%
    3.74GB   100%   100%     3.74GB   100%  main.handleRequest
         0     0%   100%     3.74GB   100%  net/http.(*ServeMux).ServeHTTP
         0     0%   100%     3.74GB   100%  net/http.(*conn).serve
         0     0%   100%     3.74GB   100%  net/http.HandlerFunc.ServeHTTP
         0     0%   100%     3.74GB   100%  net/http.serverHandler.ServeHTTP

發(fā)現(xiàn)內(nèi)存較之前增長(zhǎng)了,實(shí)際上我們可以通過(guò) -diff_base 來(lái)比較兩次采樣結(jié)果的差異:

// 第一次采樣
pprof http://localhost:8080/debug/pprof/heap > base.out

// 當(dāng)前采樣
pprof http://localhost:8080/debug/pprof/heap > current.out

// 差異分析
pprof -diff_base=base.out current.out

查看啟動(dòng)以來(lái)的內(nèi)存分配

上面的pprof實(shí)際統(tǒng)計(jì)的是采樣時(shí)刻的內(nèi)存分配情況,我們可以先清空全局內(nèi)存,然后再通過(guò)top查看,會(huì)發(fā)現(xiàn)不再有輸出了:

curl http://localhost:8080/clear
pprof  http://localhost:8080/debug/pprof/heap
(pprof) top
Showing nodes accounting for 0, 0% of 0 total
      flat  flat%   sum%        cum   cum%

但我們可以通過(guò)-sample_index=來(lái)控制采樣,對(duì)于內(nèi)存分析來(lái)說(shuō),它有下面幾種取值:

  • inuse_space:默認(rèn),表示程序在執(zhí)行時(shí)刻正在使用的內(nèi)存量;
  • inuse_objects:程序在執(zhí)行時(shí)刻正在使用的對(duì)象數(shù)量;
  • alloc_space:程序自啟動(dòng)以來(lái)分配的總內(nèi)存量,不考慮這些內(nèi)存是否已經(jīng)被釋放;
  • alloc_objects:程序自啟動(dòng)以來(lái)分配的總對(duì)象數(shù)量,不考慮這些對(duì)象是否已經(jīng)被釋放;

我們可以查看程序啟動(dòng)以來(lái)的總內(nèi)存分配數(shù)據(jù):

pprof -sample_index=alloc_space http://localhost:8080/debug/pprof/heap
(pprof) top
Showing nodes accounting for 3842.05MB, 99.44% of 3863.75MB total
Dropped 44 nodes (cum <= 19.32MB)
Showing top 10 nodes out of 14
      flat  flat%   sum%        cum   cum%
 3832.36MB 99.19% 99.19%  3832.86MB 99.20%  main.handleRequest
    9.70MB  0.25% 99.44%    19.36MB   0.5%  compress/flate.NewWriter

以上就是Golang使用pprof檢查內(nèi)存泄漏的全過(guò)程的詳細(xì)內(nèi)容,更多關(guān)于Golang pprof內(nèi)存泄漏的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • golang雙指針快速排序的實(shí)現(xiàn)代碼

    golang雙指針快速排序的實(shí)現(xiàn)代碼

    這篇文章主要介紹了golang雙指針快速排序的實(shí)現(xiàn)代碼,通過(guò)實(shí)例代碼補(bǔ)充介紹了Golang實(shí)現(xiàn)快速排序和歸并排序以及堆排序算法全注釋,需要的朋友可以參考下
    2024-03-03
  • golang 連接mongoDB的方法示例

    golang 連接mongoDB的方法示例

    這篇文章主要介紹了golang 連接mongoDB的方法示例,詳細(xì)的介紹了golang的基礎(chǔ)知識(shí)和連接mongoDB的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • Go?interface{}?轉(zhuǎn)切片類(lèi)型的實(shí)現(xiàn)方法

    Go?interface{}?轉(zhuǎn)切片類(lèi)型的實(shí)現(xiàn)方法

    本文主要介紹了Go?interface{}?轉(zhuǎn)切片類(lèi)型的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 深入了解Golang的指針用法

    深入了解Golang的指針用法

    與C語(yǔ)言一樣,Go語(yǔ)言中同樣有指針,通過(guò)指針,我們可以只傳遞變量的內(nèi)存地址,而不是傳遞整個(gè)變量,這在一定程度上可以節(jié)省內(nèi)存的占用。本文將通過(guò)示例詳細(xì)講講Golang的指針用法,需要的可以參考一下
    2022-07-07
  • 一篇文章讀懂Golang?init函數(shù)執(zhí)行順序

    一篇文章讀懂Golang?init函數(shù)執(zhí)行順序

    init()函數(shù)會(huì)在包被初始化后自動(dòng)執(zhí)行,并且在main()函數(shù)之前執(zhí)行,但是需要注意的是init()以及main()函數(shù)都是無(wú)法被顯式調(diào)用的,下面這篇文章主要給大家介紹了關(guān)于如何通過(guò)一篇文章讀懂Golang?init函數(shù)執(zhí)行順序的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • 基于Golang實(shí)現(xiàn)Redis分布式鎖解決秒殺問(wèn)題

    基于Golang實(shí)現(xiàn)Redis分布式鎖解決秒殺問(wèn)題

    這篇文章主要給大家介紹了使用Golang實(shí)現(xiàn)Redis分布式鎖解決秒殺問(wèn)題,文中有詳細(xì)的代碼示例供大家參考,具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-08-08
  • 一文帶你吃透Go語(yǔ)言中的原子操作

    一文帶你吃透Go語(yǔ)言中的原子操作

    原子操作是解決并發(fā)編程中共享數(shù)據(jù)訪問(wèn)問(wèn)題的一種常見(jiàn)機(jī)制,下面就來(lái)和大家深入介紹原子操作的原理、用法以及在解決并發(fā)問(wèn)題中的應(yīng)用,需要的可以參考一下
    2023-06-06
  • 詳解Go中處理時(shí)間數(shù)據(jù)的方法

    詳解Go中處理時(shí)間數(shù)據(jù)的方法

    在許多場(chǎng)合,你將不得不編寫(xiě)必須處理時(shí)間的代碼。在Go中處理時(shí)間數(shù)據(jù)需要你從Go標(biāo)準(zhǔn)庫(kù)中導(dǎo)入?time?包。這個(gè)包有很多方法和類(lèi)型供你使用,但我選取了最常用的方法和類(lèi)型,并在這篇文章中進(jìn)行了描述,感興趣的可以了解一下
    2023-04-04
  • Go語(yǔ)言中validation庫(kù)不能校驗(yàn)零值問(wèn)題的解決方法

    Go語(yǔ)言中validation庫(kù)不能校驗(yàn)零值問(wèn)題的解決方法

    在使用 Gin 框架的時(shí)候,前后端傳遞數(shù)據(jù)的時(shí)候,比如使用 JSON 格式,通常會(huì)使用 ShouldBindJSON 去用結(jié)構(gòu)體打 tag 綁定前端傳來(lái)的 JSON 格式數(shù)據(jù),本文給大家介紹了Go語(yǔ)言中validation庫(kù)不能校驗(yàn)零值問(wèn)題的解決方法,需要的朋友可以參考下
    2024-08-08
  • Golang語(yǔ)言使用像JAVA?Spring注解一樣的DI和AOP依賴注入實(shí)例

    Golang語(yǔ)言使用像JAVA?Spring注解一樣的DI和AOP依賴注入實(shí)例

    這篇文章主要為大家介紹了Golang語(yǔ)言使用像JAVA?Spring注解一樣的DI和AOP依賴注入實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10

最新評(píng)論