Golang初學:獲取程序內存使用情況,std runtime

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 相關代碼

前】、中】 相同,後】 的內存使用 會多一點。

前】
Alloc = 0 MiB
TotalAlloc = 0 MiB
Sys = 6 MiB
HeapAlloc = 0 MiB
HeapSys = 3 MiB
NumGC = 0
s1: len=1000000 cap=1000000

中】
Alloc = 0 MiB
TotalAlloc = 7 MiB
Sys = 14 MiB
HeapAlloc = 0 MiB
HeapSys = 11 MiB
NumGC = 1

後】
Alloc = 0 MiB
TotalAlloc = 7 MiB
Sys = 14 MiB
HeapAlloc = 0 MiB
HeapSys = 11 MiB
NumGC = 1

 

2、 增加 填充數據部分

前】、中】 和 之前相同,後】  增加了很多,這裏 1百萬 的數據,後】 的 Sys 達到了 54MB。

前】
Alloc = 0 MiB
TotalAlloc = 0 MiB
Sys = 6 MiB
HeapAlloc = 0 MiB
HeapSys = 3 MiB
NumGC = 0
s1: len=1000000 cap=1000000

中】
Alloc = 7 MiB
TotalAlloc = 7 MiB
Sys = 14 MiB
HeapAlloc = 7 MiB
HeapSys = 11 MiB
NumGC = 1

後】
Alloc = 0 MiB
TotalAlloc = 62 MiB
Sys = 54 MiB
HeapAlloc = 0 MiB
HeapSys = 51 MiB
NumGC = 5

ben發佈於博客園

3、再增加 time.Sleep 部分

1、3 秒都行。

前】
Alloc = 0 MiB
TotalAlloc = 0 MiB
Sys = 6 MiB
HeapAlloc = 0 MiB
HeapSys = 3 MiB
NumGC = 0
s1: len=1000000 cap=1000000

中】
Alloc = 7 MiB
TotalAlloc = 7 MiB
Sys = 14 MiB
HeapAlloc = 7 MiB
HeapSys = 11 MiB
NumGC = 1

後】
Alloc = 0 MiB
TotalAlloc = 62 MiB
Sys = 55 MiB
HeapAlloc = 0 MiB
HeapSys = 51 MiB
NumGC = 5

 

測試小結

ReadMemStats 函數 獲取的內存信息,存在一些延遲——毫秒級,使用時需要注意。

 

控制 golang 程序內存使用的方式

兩千萬數據量的測試結果

在上面的程序中, 數據量是 一百萬,將其增加到 二千萬 進行測試,其內存分配肯定會增加很多。

結果如下:其最終 Sys 達到了 895MBben發佈於博客園

要是數據量再增大若干倍,只怕我的測試電腦要崩潰了,或者,程序先崩潰。

前】
Alloc = 0 MiB
TotalAlloc = 0 MiB
Sys = 5 MiB
HeapAlloc = 0 MiB
HeapSys = 3 MiB
NumGC = 0
s1: len=20000000 cap=20000000

中】
Alloc = 152 MiB
TotalAlloc = 152 MiB
Sys = 162 MiB
HeapAlloc = 152 MiB
HeapSys = 159 MiB
NumGC = 1

後】
Alloc = 0 MiB
TotalAlloc = 1252 MiB
Sys = 895 MiB
HeapAlloc = 0 MiB
HeapSys = 891 MiB
NumGC = 4

 

初步探索

諮詢了 #通義千問 ,其介紹了兩種方式:

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發佈於博客園

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章