go version go1.22.1 windows/amd64
Windows 11 + amd64
x86_64 x86_64 GNU/Linux
---
序章
本文介紹 golang 程序 佔用內存的監控:
使用 std runtime 的 ReadMemStats 函數。
ReadMemStats 函數
https://pkg.go.dev/[email protected]
// 函數
func ReadMemStats(m *MemStats)
// 結構體
type MemStats struct {
// 多個公開字段
}
ReadMemStats 介紹:
ReadMemStats populates m with memory allocator statistics. The returned memory allocator statistics are up to date as of the call to ReadMemStats. This is in contrast with a heap profile, which is a snapshot as of the most recently completed garbage collection cycle. |
翻譯: 讀取模塊統計數據用內存分配器統計信息填充 m。 返回的內存分配器統計信息是在調用讀取內存統計數據時的最新數據。 這與堆配置文件形成對比,它是最近完成的垃圾收集週期的快照。 ——金山詞霸 |
測試代碼
場景:製造一個長度爲n的切片,再往其中填充數據,檢查 前、中、後 三個內存使用情況。ben發佈於博客園
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Println("前】")
readMem()
const slen = 1_000_000
s1 := make([]int, slen)
fmt.Printf("s1: len=%d cap=%d\n", len(s1), cap(s1))
time.Sleep(3 * time.Second) // 必須,否則,下面這個 readMem() 的結果和上面的相同
fmt.Println("\n中】")
readMem()
// 填充數據
// 填充後,內存使用纔有變化
for i := range [slen]struct{}{} {
s1 = append(s1, i)
}
time.Sleep(3 * time.Second) // 非必須
fmt.Println("\n後】")
readMem()
}
func readMem() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
// fmt.Println(ms) // 太複雜了
// 內存 通義千問
// 打印一些關鍵的內存統計信息
fmt.Printf("Alloc = %v MiB\n", m.Alloc/1024/1024) // 分配但未釋放的內存
fmt.Printf("TotalAlloc = %v MiB\n", m.TotalAlloc/1024/1024) // 程序啓動以來分配的總內存
fmt.Printf("Sys = %v MiB\n", m.Sys/1024/1024) // 從操作系統分配的總內存
fmt.Printf("HeapAlloc = %v MiB\n", m.HeapAlloc/1024/1024) // 從堆上分配但未釋放的內存
fmt.Printf("HeapSys = %v MiB\n", m.HeapSys/1024/1024) // 由Go分配的堆內存的系統內存大小
fmt.Printf("NumGC = %v\n", m.NumGC) // 進行的GC次數
}
注意其中的 1)time.Sleep,2)填充數據 兩部分,下面測試期間 可能會註釋掉。
測試結果
3種情況的測試結果。
1、沒有 填充數據、time.Sleep 相關代碼
前】、中】 相同,後】 的內存使用 會多一點。
前】 中】 後】 |
2、 增加 填充數據部分
前】、中】 和 之前相同,後】 增加了很多,這裏 1百萬 的數據,後】 的 Sys 達到了 54MB。
前】 中】 後】 |
ben發佈於博客園
3、再增加 time.Sleep 部分
1、3 秒都行。
前】 中】 後】 |
測試小結
ReadMemStats 函數 獲取的內存信息,存在一些延遲——毫秒級,使用時需要注意。
控制 golang 程序內存使用的方式
兩千萬數據量的測試結果
在上面的程序中, 數據量是 一百萬,將其增加到 二千萬 進行測試,其內存分配肯定會增加很多。
結果如下:其最終 Sys 達到了 895MB!ben發佈於博客園
要是數據量再增大若干倍,只怕我的測試電腦要崩潰了,或者,程序先崩潰。
前】 中】 後】 |
初步探索
諮詢了 #通義千問 ,其介紹了兩種方式:
1、間接方式:Docker
示例,
docker run -it --memory="512m" --cpus="0.5" your-image-name
2、直接方式:Linux 下的 cgroups
2.1、在 golang 程序中使用 cgroups
若需直接在Go程序中操作cgroups,可以使用第三方庫,
如`github.com/opencontainers/runc/libcontainer`或`github.com/containerd/cgroups`。
注,cgroups v1 和 v2 有些差別。
注,未親測 TODO。
ben發佈於博客園
間接方式 不用多說,現在都用上 Docker、Kubernetes 了,很簡單。
直接方式:需要做更多探索。要知道,cgroups 也是 容器技術 的底層,瞭解並掌握是有很多好處的。
END.
ben發佈於博客園
本文鏈接:
https://www.cnblogs.com/luo630/p/18198598
ben發佈於博客園
參考資料
1、通義千問
https://tongyi.aliyun.com/qianwen/
2、
ben發佈於博客園
ben發佈於博客園