[英]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/time
是1056992 KiB
,它太大了四倍。 這是您的/usr/bin/time
版本中的錯誤, ru_maxrss
以KBytes而不是頁面報告。 我的Ubuntu版本已修補。
參考文獻:
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.