我正在運行一種情況,即go程序佔用15gig的虛擬內存並繼續增長。這個問題只發生在我們的CentOS服務器上。在我的OSX開發機上,我無法複製它。執行併發操作時出現內存泄露os/exec.Command.Wait()
我有沒有發現在旅途中的bug,還是我錯誤地做一些事情?
我煮完問題降低到一個簡單的演示,我將現在描述。首先生成並運行此去服務器:
package main
import (
"net/http"
"os/exec"
)
func main() {
http.HandleFunc("/startapp", startAppHandler)
http.ListenAndServe(":8081", nil)
}
func startCmd() {
cmd := exec.Command("/tmp/sleepscript.sh")
cmd.Start()
cmd.Wait()
}
func startAppHandler(w http.ResponseWriter, r *http.Request) {
startCmd()
w.Write([]byte("Done"))
}
做一個/tmp/sleepscript.sh文件命名,並執行命令chmod 755
#!/bin/bash
sleep 5
然後使多個併發的請求/的startApp。在bash shell,你可以這樣來做:
for i in {1..300}; do (curl http://localhost:8081/startapp &); done
的VIRT內存現在應該是幾個GB。如果你重新運行上面的for循環,VIRT內存每次都會繼續增加千兆字節。
更新1:問題是我在CentOS上遇到了OOM問題。 (謝謝@nos)
更新2:通過使用daemonize
解決了問題並將調用同步到Cmd.Run()
。謝謝@JimB確認運行在它自己的線程中的.Wait()
是POSIX API的一部分,並且沒有辦法避免在不泄漏資源的情況下調用.Wait()
。
VirtualMemory,特別是在OSX上,是沒有意義的。 RSS對於該進程起訴的內存量有一個更好的指導。 – JimB
提示:[Run()](https://golang.org/pkg/os/exec/#Cmd.Run)執行該進程並掛起,直到它退出。 –
我還建議分配一個[goroutines池](https://gobyexample.com/worker-pools)來限制同時運行的進程數量。 –