go 的内存使用疑问

chesha1 · 2024-8-28 10:21:44 · 58 次点击
下面这段代码:
```go
package main

import (
        "fmt"
        "runtime"
        "unique"
)

func printMemUsage() {
        var m runtime.MemStats
        runtime.ReadMemStats(&m)

        fmt.Printf("Alloc = %v B", m.Alloc)
        fmt.Printf("\tTotalAlloc = %v B", m.TotalAlloc)
        fmt.Printf("\n")
}

type TestStruct struct {
        A float64
        B float64
        C float64
        D float64
}

func main() {
        testobj1 := TestStruct{A: 1, B: 2, C: 3, D: 4}
        printMemUsage()

        testobj2 := TestStruct{A: 1, B: 2, C: 3, D: 4}
        printMemUsage()

        testobj3 := TestStruct{A: 1, B: 2, C: 3, D: 4}
        printMemUsage()

        testobj4 := TestStruct{A: 1, B: 2, C: 3, D: 4}
        printMemUsage()
        fmt.Println(testobj1, testobj2, testobj3, testobj4)
        fmt.Println("---------")

        uniqueobj1 := unique.Make(TestStruct{A: 1, B: 2, C: 3, D: 4})
        printMemUsage()

        uniqueobj2 := unique.Make(TestStruct{A: 1, B: 2, C: 3, D: 4})
        printMemUsage()

        uniqueobj3 := unique.Make(TestStruct{A: 1, B: 2, C: 3, D: 4})
        printMemUsage()

        uniqueobj4 := unique.Make(TestStruct{A: 1, B: 2, C: 3, D: 4})
        printMemUsage()
        fmt.Println(uniqueobj1, uniqueobj2, uniqueobj3, uniqueobj4)
        fmt.Println("---------")

        testobj5 := TestStruct{A: 1, B: 2, C: 3, D: 4}
        printMemUsage()

        testobj6 := TestStruct{A: 1, B: 2, C: 3, D: 4}
        printMemUsage()

        testobj7 := TestStruct{A: 1, B: 2, C: 3, D: 4}
        printMemUsage()

        testobj8 := TestStruct{A: 1, B: 2, C: 3, D: 4}
        printMemUsage()
        fmt.Println(&testobj5, &testobj6, &testobj7, &testobj8)

}
```

输出结果是:
```
Alloc = 118256 B        TotalAlloc = 118256 B
Alloc = 119704 B        TotalAlloc = 119704 B
Alloc = 119720 B        TotalAlloc = 119720 B
Alloc = 119736 B        TotalAlloc = 119736 B
{1 2 3 4} {1 2 3 4} {1 2 3 4} {1 2 3 4}
---------
Alloc = 121056 B        TotalAlloc = 121056 B
Alloc = 121072 B        TotalAlloc = 121072 B
Alloc = 121088 B        TotalAlloc = 121088 B
Alloc = 121104 B        TotalAlloc = 121104 B
{0x1400001e180} {0x1400001e180} {0x1400001e180} {0x1400001e180}
---------
Alloc = 121152 B        TotalAlloc = 121152 B
Alloc = 121200 B        TotalAlloc = 121200 B
Alloc = 121248 B        TotalAlloc = 121248 B
Alloc = 121296 B        TotalAlloc = 121296 B
&{1 2 3 4} &{1 2 3 4} &{1 2 3 4} &{1 2 3 4}
```

本来是想试一下 unique 包对于内存的节约效果的,但是没想到第一种写法,每次也只增加了 16B ,和用了 unique 效果一样

而第三种写法,和第一种相比,确实每次用的内存多了,但是为什么后面的 fmt.Println 的写法区别,能影响前面的内存使用量

版本:go 1.23.0

平台:arm macos
举报· 58 次点击
登录 注册 站外分享
5 条回复  
leonshaw 小成 2024-8-28 15:51:42
第一个在栈上的,第三个逃逸了
picone 小成 2024-8-28 15:39:22
@xiaozirun 有优化的,实际上他就是 Java 的 string intern ,只不过他支持泛型而已。

https://github.com/golang/go/issues/62483
xiaozirun 小成 2024-8-28 15:32:50
unique 包对内存使用有优化效果吗,官方文档似乎只说了,他是只是用实现快速比等。
文档: https://pkg.go.dev/unique
whoami9894 小成 2024-8-28 14:43:42
1. 栈上的变量编译后就是一个 `sub rsp, N`,内存用量不会变的
2. fmt.Print 内部有一个内存池
3. 打印结构体指针需要先反射判断是指针,打印一个 `&`,再递归打印结构体
matrix1010 小成 2024-8-28 11:24:04
你有没有注意到 TestStruct 其实是 32 bytes 的,那 Alloc 应该以 32 为单位增加。但你这里是 16 bytes 。有一个东西恰好是 16 bytes: reflect.StringHeader
返回顶部