• golang context 内存大小


    写代码时,经常会使用context.WithTimeout,传入某个goroutine。不小心会忘记执行defer cancel()。从而导致context泄露。具体泄露多少内存呢?

    我写了一个程序来计算大小:

    1. package main
    2. import (
    3. "context"
    4. "fmt"
    5. "runtime"
    6. "time"
    7. "unsafe"
    8. "github.com/DmitriyVTitov/size"
    9. )
    10. func bToMb(b uint64) uint64 {
    11. return b / 1024 / 1024
    12. }
    13. func PrintMemUsage() {
    14. var m runtime.MemStats
    15. runtime.ReadMemStats(&m)
    16. // For info on each, see: https://golang.org/pkg/runtime/#MemStats
    17. fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
    18. fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
    19. fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
    20. fmt.Printf("\tNumGC = %v\n", m.NumGC)
    21. }
    22. func main() {
    23. PrintMemUsage()
    24. ctx, cancle := context.WithTimeout(context.Background(), time.Duration(time.Second*1))
    25. defer cancle()
    26. fmt.Println("sizeof(ctx) :", unsafe.Sizeof(ctx))
    27. fmt.Println(size.Of(ctx))
    28. //time.Sleep(time.Second * 20)
    29. fmt.Println("sleep finish")
    30. len := 1024 * 10
    31. for i := 0; i < len ; i ++ {
    32. context.WithTimeout(context.Background(), time.Duration(time.Second*10))
    33. }
    34. PrintMemUsage()
    35. }

    执行结果如下:

    1. Alloc = 0 MiB TotalAlloc = 0 MiB Sys = 8 MiB NumGC = 0
    2. sizeof(ctx) : 16
    3. 254
    4. sleep finish
    5. Alloc = 2 MiB TotalAlloc = 2 MiB Sys = 8 MiB NumGC = 0

    可以发现使用unsafe.Sizeof计算出来的大小是不对的。

    系统增加了2M内存,即2*1024KB,2*1024/(1024 *10) = 0.2KB = 0.2*1024 = 204B接近254字节。可能是数字太小导致误差太大。我们循环调成 1024*1024。重新执行一遍,结果如下:

    1. Alloc = 0 MiB TotalAlloc = 0 MiB Sys = 8 MiB NumGC = 0
    2. sizeof(ctx) : 16
    3. 254
    4. sleep finish
    5. Alloc = 215 MiB TotalAlloc = 248 MiB Sys = 236 MiB NumGC = 7

    增加了 240M内存,即每个大小为240字节,差了14字节。

    在代码中加上debug.SetGCPercent(-1) 代码,禁用gc。代码如下:

    1. package main
    2. import (
    3. "context"
    4. "fmt"
    5. "runtime"
    6. "runtime/debug"
    7. "time"
    8. "unsafe"
    9. "github.com/DmitriyVTitov/size"
    10. )
    11. func bToMb(b uint64) uint64 {
    12. return b / 1024 / 1024
    13. }
    14. func PrintMemUsage() {
    15. var m runtime.MemStats
    16. runtime.ReadMemStats(&m)
    17. // For info on each, see: https://golang.org/pkg/runtime/#MemStats
    18. fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
    19. fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
    20. fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
    21. fmt.Printf("\tNumGC = %v\n", m.NumGC)
    22. }
    23. func main() {
    24. debug.SetGCPercent(-1)
    25. PrintMemUsage()
    26. ctx, cancle := context.WithTimeout(context.Background(), time.Duration(time.Second*1))
    27. defer cancle()
    28. fmt.Println("sizeof(ctx) :", unsafe.Sizeof(ctx))
    29. fmt.Println(size.Of(ctx))
    30. //time.Sleep(time.Second * 20)
    31. fmt.Println("sleep finish")
    32. len := 1024*1024
    33. for i := 0; i < len ; i ++ {
    34. context.WithTimeout(context.Background(), time.Duration(time.Second*30))
    35. }
    36. PrintMemUsage()
    37. }

    运行结果如下:

    1. Alloc = 0 MiB TotalAlloc = 0 MiB Sys = 8 MiB NumGC = 0
    2. sizeof(ctx) : 16
    3. 254
    4. sleep finish
    5. Alloc = 247 MiB TotalAlloc = 247 MiB Sys = 267 MiB NumGC = 0

    这样误差就更小了。

    说明"github.com/DmitriyVTitov/size" 是可信的。此工具是基于go的binary.Size来计算的。

  • 相关阅读:
    TortoiseGit安装教程(Windows)
    Java 基础 --- Java变量储存机制及参数传递
    推荐10款C#开源好用的Windows软件
    别看了,这就是你的题呀
    sql中可以使用不在select中的字段排序
    冒泡排序
    【数据结构】二叉树必刷题
    Keepalived工具的基本介绍(原理:VRRP协议)
    get√接口自动化核心知识点浓缩,为面试加分
    聊一聊Rust的enum
  • 原文地址:https://blog.csdn.net/guoguangwu/article/details/127615353