簡體   English   中英

在Go中分析內存時看似不一致的結果

[英]Seemingly inconsistent results when profiling memory in Go

我最近在大型數據集上運行了一些用Go編寫的數字代碼,並且遇到了內存管理問題。 在嘗試分析問題時,我以三種不同的方式測量了程序的內存使用情況:使用Go的runtime/pprof包,使用unix time實用程序,以及手動runtime/pprof我分配的數據大小。 這三種方法並沒有給我一致的結果。

下面是我正在分析的代碼的簡化版本。 它分配了幾個切片,將值放在每個索引處,並將每個切片放在父切片中:

package main

import (
    "fmt"
    "os"

    "runtime/pprof"
    "unsafe"
    "flag"
)

var mprof = flag.String("mprof", "", "write memory profile to this file")

func main() {
    flag.Parse()

    N := 1<<15
    psSlice := make([][]int64, N)
    _ = psSlice
    size := 0

    for i := 0; i < N; i++ {
        ps := make([]int64, 1<<10)
        for i := range ps { ps[i] = int64(i) }
        psSlice[i] = ps
        size += int(unsafe.Sizeof(ps[0])) * len(ps)
    }

    if *mprof != "" {
        f, err := os.Create(*mprof)
        if err != nil { panic(err) }
        pprof.WriteHeapProfile(f)
        f.Close()
    }

    fmt.Printf("total allocated: %d MB\n", size >> 20)
}

使用命令$ time time -f "%M kB" ./mem_test -mprof=out.mprof運行此命令$ time time -f "%M kB" ./mem_test -mprof=out.mprof導致輸出:

total allocated: 256 MB
1141216 kB

real    0m0.150s
user    0m0.031s
sys 0m0.113s

這里第一個數字,256 MB,只是從unsafe.Sizeof計算的數組的大小,第二個數字,1055 MB,是time報告。 運行pprof工具會導致

(pprof) top1
Total: 108.2 MB
   107.8  99.5%  99.5%    107.8  99.5% main.main

對於較小或較大長度的切片,這些結果可以按照您期望的方式平滑地縮放。

為什么這三個數字不緊密排列?

首先,您需要提供一個無錯誤的示例。 讓我們從基本數字開始。 例如,

package main

import (
    "fmt"
    "runtime"
    "unsafe"
)

func WriteMatrix(nm [][]int64) {
    for n := range nm {
        for m := range nm[n] {
            nm[n][m]++
        }
    }
}

func NewMatrix(n, m int) [][]int64 {
    a := make([]int64, n*m)
    nm := make([][]int64, n)
    lo, hi := 0, m
    for i := range nm {
        nm[i] = a[lo:hi:hi]
        lo, hi = hi, hi+m
    }
    return nm
}

func MatrixSize(nm [][]int64) int64 {
    size := int64(0)
    for i := range nm {
        size += int64(unsafe.Sizeof(nm[i]))
        for j := range nm[i] {
            size += int64(unsafe.Sizeof(nm[i][j]))
        }
    }
    return size
}

var nm [][]int64

func main() {
    n, m := 1<<15, 1<<10
    var ms1, ms2 runtime.MemStats
    runtime.ReadMemStats(&ms1)
    nm = NewMatrix(n, m)
    WriteMatrix(nm)
    runtime.ReadMemStats(&ms2)
    fmt.Println(runtime.GOARCH, runtime.GOOS)
    fmt.Println("Actual:  ", ms2.TotalAlloc-ms1.TotalAlloc)
    fmt.Println("Estimate:", n*3*8+n*m*8)
    fmt.Println("Total:   ", ms2.TotalAlloc)
    fmt.Println("Size:    ", MatrixSize(nm))

    // check top VIRT and RES for COMMAND peter
    for {
        WriteMatrix(nm)
    }
}

輸出:

$ go build peter.go && /usr/bin/time -f "%M KiB" ./peter
amd64 linux
Actual:   269221888
Estimate: 269221888
Total:    269240592
Size:     269221888
^C
Command exited with non-zero status 2
265220 KiB
$

$ top
VIRT 284268 RES 265136 COMMAND peter

這是你所期望的嗎?

有關計算內存大小的正確方法,請參閱MatrixSize

在允許我們使用top命令的無限循環中,通過更新矩陣將矩陣固定為常駐。

運行此程序時會得到什么結果?


BUG:

/usr/bin/time1056992 KiB ,它太大了四倍。 這是您的/usr/bin/time版本中的錯誤, ru_maxrss以KBytes而不是頁面報告。 我的Ubuntu版本已修補。

參考文獻:

Re:GNU時間:結果不正確

時間1.7計算Linux上的rusage錯誤

GNU項目檔案:時間

Ubuntu中的“時間”1.7-24源代碼包 ru_maxrss以KBytes而不是頁面報告。 (關閉:#649402)

#PATY]時間過高估計最多RSS 4倍 - Debian Bug報告日志

主題:修復ru_maxrss報告作者:Richard Kettlewell Bug-Debian: http ://bugs.debian.org/cgi-bin/bugreport.cgi?video = 649402

 --- time-1.7.orig/time.c +++ time-1.7/time.c @@ -392,7 +398,7 @@ ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v)); break; case 'M': /* Maximum resident set size. */ - fprintf (fp, "%lu", ptok ((UL) resp->ru.ru_maxrss)); + fprintf (fp, "%lu", (UL) resp->ru.ru_maxrss); break; case 'O': /* Outputs. */ fprintf (fp, "%ld", resp->ru.ru_oublock); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM