golang context 内存大小

44 篇文章 0 订阅
17 篇文章 3 订阅

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

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

package main

import (
	"context"
	"fmt"
	"runtime"
	"time"
	"unsafe"
	"github.com/DmitriyVTitov/size"
)


func bToMb(b uint64) uint64 {
	return b / 1024 / 1024
}

func PrintMemUsage() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	// For info on each, see: https://golang.org/pkg/runtime/#MemStats
	fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
	fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
	fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
	fmt.Printf("\tNumGC = %v\n", m.NumGC)
}

func main() {
	PrintMemUsage()
	ctx, cancle := context.WithTimeout(context.Background(), time.Duration(time.Second*1))
	defer cancle()
	fmt.Println("sizeof(ctx) :", unsafe.Sizeof(ctx))
	fmt.Println(size.Of(ctx))

	//time.Sleep(time.Second * 20)
	fmt.Println("sleep finish")

	len := 1024 * 10
	for i := 0; i < len ; i ++ {
		context.WithTimeout(context.Background(), time.Duration(time.Second*10))
	}
	PrintMemUsage()

}

执行结果如下:

Alloc = 0 MiB   TotalAlloc = 0 MiB      Sys = 8 MiB     NumGC = 0
sizeof(ctx) : 16
254
sleep finish
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。重新执行一遍,结果如下:

Alloc = 0 MiB   TotalAlloc = 0 MiB      Sys = 8 MiB     NumGC = 0
sizeof(ctx) : 16
254
sleep finish
Alloc = 215 MiB TotalAlloc = 248 MiB    Sys = 236 MiB   NumGC = 7

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

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

package main

import (
	"context"
	"fmt"
	"runtime"
	"runtime/debug"
	"time"
	"unsafe"
	"github.com/DmitriyVTitov/size"
)


func bToMb(b uint64) uint64 {
	return b / 1024 / 1024
}

func PrintMemUsage() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	// For info on each, see: https://golang.org/pkg/runtime/#MemStats
	fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
	fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
	fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
	fmt.Printf("\tNumGC = %v\n", m.NumGC)
}

func main() {
	debug.SetGCPercent(-1)
	PrintMemUsage()
	ctx, cancle := context.WithTimeout(context.Background(), time.Duration(time.Second*1))
	defer cancle()
	fmt.Println("sizeof(ctx) :", unsafe.Sizeof(ctx))
	fmt.Println(size.Of(ctx))

	//time.Sleep(time.Second * 20)
	fmt.Println("sleep finish")

	len := 1024*1024
	for i := 0; i < len ; i ++ {
		context.WithTimeout(context.Background(), time.Duration(time.Second*30))
	}
	PrintMemUsage()

}

运行结果如下:

Alloc = 0 MiB   TotalAlloc = 0 MiB      Sys = 8 MiB     NumGC = 0
sizeof(ctx) : 16
254
sleep finish
Alloc = 247 MiB TotalAlloc = 247 MiB    Sys = 267 MiB   NumGC = 0

这样误差就更小了。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值