我在使用 golangs lib encoding/base64 的軟體中遇到記憶體消耗問題
我的軟體將視頻檔案拆分為單獨的影像,(gocv mat)將它們轉換為base64字串并將其保存為json格式的檔案。
在測驗程序中,我發現記憶體使用量一直在增加,直到 oom-reaper 殺死行程。
對 pprof 的調查顯示編碼/base64 記憶體似乎堆積了起來。
我在每個影像幀之后進行了 pprof 快照,并且分配的編碼/base64 記憶體在 oom-reaper 終止行程之前不久從 976.89kB(flat)上升到 4633.54kB(flat)。
Beginning:
flat flat% sum% cum cum%
976.89kB 32.29% 32.29% 976.89kB 32.29% encoding/base64.(*Encoding).EncodeToString
512.50kB 16.94% 49.23% 512.50kB 16.94% runtime.allocm
512.20kB 16.93% 66.15% 512.20kB 16.93% runtime.malg
512.05kB 16.92% 83.08% 1488.94kB 49.21% runtime.main
512kB 16.92% 100% 512kB 16.92% time.resetTimer (inline)
0 0% 100% 976.89kB 32.29% main.Process
End:
Showing nodes accounting for 6170.44kB, 100% of 6170.44kB total
flat flat% sum% cum cum%
4633.54kB 75.09% 75.09% 4633.54kB 75.09% encoding/base64.(*Encoding).EncodeToString
1024.41kB 16.60% 91.69% 1024.41kB 16.60% runtime.malg
512.50kB 8.31% 100% 512.50kB 8.31% runtime.allocm
0 0% 100% 4633.54kB 75.09% main.Process
串列向我顯示了與其對應的代碼:
(pprof) list encoding/base64
Total: 2.95MB
ROUTINE ======================== encoding/base64.(*Encoding).EncodeToString in /usr/local/go/src/encoding/base64/base64.go
976.89kB 976.89kB (flat, cum) 32.29% of Total
. . 175:
. . 176:// EncodeToString returns the base64 encoding of src.
. . 177:func (enc *Encoding) EncodeToString(src []byte) string {
. . 178: buf := make([]byte, enc.EncodedLen(len(src)))
. . 179: enc.Encode(buf, src)
976.89kB 976.89kB 180: return string(buf)
. . 181:}
. . 182:
. . 183:type encoder struct {
. . 184: err error
. . 185: enc *Encoding
所以在我的 golang 代碼中,相應的代碼行是:
func Process(img gocv.Mat) ( myImage Images ){
detectImg, detectClass, detectBoxes := Detect(&net,
img.Clone(),
0.45, 0.5,
OutputNames, classes)
defer detectImg.Close()
// convert gocv.Mat to []bytes
myImg , _ := detectImg.ToImage()
myJPG := new(bytes.Buffer)
jpeg.Encode(myJPG, myImg, &jpeg.Options{95})
myBytes := myJPG.Bytes()
// memory consuming
encodedString := base64.StdEncoding.EncodeToString(myBytes)
// [...]
return myImage
}
在這種情況下,如何釋放“encodedString”的記憶體而不堆積?(更新:答案說這沒有必要也不可能)
Or is it maybe not my wrong coding, and the mem-leak is at the lib base64 ?? (Update: Answers say this is surely not the case)
uj5u.com熱心網友回復:
要回答您的問題:
在這種情況下,如何釋放“encodedString”的記憶體而不堆積?
你不能也不需要。未使用的記憶體被“釋放”。
或者這可能不是我的錯誤編碼,而 mem-leak 位于 lib base64 ?
不,包 encoding/base64 沒有記憶體泄漏。(您在垃圾收集語言的標準庫中的一個普通函式中檢測到記憶體泄漏的可能性為 0。)
指導您找到解決方案:
您的應用程式使用了荒謬的記憶體量,但這是因為 a) 處理視頻和影像會占用大量記憶體,并且 b) 您似乎沒有采取任何措施來保持低記憶體:例如,您將整個影像編碼為 bytes.Buffer,然后對整個位元組進行編碼。緩沖到一個字串,然后處理該字串,依此類推。您可能應該將影像編碼為stream,將此流編碼為 base64 并將此輸出進一步流式傳輸到它存放的位置。這在 Go 中完全沒有痛苦,因為所有這些編碼器都在 io.Writers 上作業,可以很容易地鏈接起來。
uj5u.com熱心網友回復:
我上面的問題是完全錯誤的方式。
Base64 根本不是問題,它只是 pprof 顯示的最大記憶體消耗者,導致我得出一個錯誤的結論,即 base64 是問題所在。
我猜 pprof 會告訴我我的 go 程式的所有記憶體消耗,包括 gocv。gocv 是 opencv 的 ac 包裝器,但是 pprof 看不到它的記憶體消耗,因為它是 c 代碼!(我在問這個問題時不知道)。由于 pprof 可見的記憶體消耗沒有顯示 c-wrapper 庫使用的記憶體,例如 gocv。golang 根本看不到大部分記憶體消耗。所以 JimB 的幫助提示是:
看到您如何在 opencv 周圍使用 Go 包裝器,您關心的記憶體可能甚至沒有被 Go 分配。在這種情況下,您確實需要確保所有內容都可能根據他們的檔案關閉或發布,因為大部分作業是在 C 中完成的,而不是 Go。但是,即使您正在正確清理,您仍然需要了解您的記憶體限制,并確保您在任何給定點都不會嘗試保存太多資料。
當我清理 gocv 物件時,記憶體消耗顯著下降。我曾經關閉物件:
defer obj.close()
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/422101.html
標籤:
