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/runtime@go1.22.3

// 函数
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发布于博客园

 

posted @ 2024-05-17 21:21  快乐的二当家815  阅读(261)  评论(0编辑  收藏  举报