go语言的map回收机制
在 Golang 中的 map 结构,在删除键值对的时候,并不会真正的删除,只是标记当前的key状态为empty。我们下面的程序作为例子,看看当我们在删除map中键值对时的内存变化,并了解如才能真正实现对键值对的垃圾回收。
initMap()
package main
import (
"log"
"runtime"
)
var lastFreed uint64
type element struct {
X int
Y int
}
var EleMap map[int]*element
const Num = 10000
func main() {
printMemory()
runtime.GC()
initMap()
runtime.GC()
printMemory()
delMap()
runtime.GC()
printMemory()
EleMap = nil
runtime.GC()
printMemory()
}
func initMap() {
EleMap = make(map[int]*element)
for i := 0; i < Num; i++ {
EleMap[i] = &element{i * 2, i * 3}
}
}
func delMap() {
for i := 0; i < Num; i++ {
delete(EleMap, i)
}
}
func printMemory() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
log.Printf("Alloc=%v||TotalAlloc=%v||Just_Freed=%v||Sys=%v||numGc=%v\n",
m.Alloc/1024, m.TotalAlloc/1024, ((m.TotalAlloc-m.Alloc)-lastFreed)/1024, m.Sys/1024, m.NumGC)
lastFreed = m.TotalAlloc - m.Alloc
}
程序运行结果如下:
2022/02/09 22:38:38 Alloc=159||TotalAlloc=159||Just_Freed=0||Sys=8019||numGc=0
2022/02/09 22:38:38 Alloc=628||TotalAlloc=991||Just_Freed=362||Sys=8658||numGc=2
2022/02/09 22:38:38 Alloc=474||TotalAlloc=993||Just_Freed=156||Sys=8658||numGc=3
2022/02/09 22:38:38 Alloc=162||TotalAlloc=994||Just_Freed=313||Sys=8914||numGc=4
通过第三行日志可以看出,当我们删除所有的键值对,并执行垃圾回收之后,当前分配的内存为474,而非初始状态的内存159。可以看出有相当一部分内存并没有被回收。因此删除键值对并不能保证背后的内存也被回收。
在某些系统中,map会作为缓存来存储数据,即使按照超时时间,定期删除某些键值对,也难以保证缓存占用的内存会被释放,会导致系统有内存泄漏的风险。