go 语言的 map 回收机制
在 Golang 中的 map 构造,在删除键值对的时候,并不会真正的删除,只是标记以后的 key 状态为 empty。咱们上面的程序作为例子,看看当咱们在删除 map 中键值对时的内存变动,并理解如能力真正实现对键值对的垃圾回收。
程序根本流程为:在 initMap()
中,向 map 构造中插入 10000 对键值对,而后在全副删除,通过 runtime.MemStats 打印内存应用状况。
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 会作为缓存来存储数据,即便依照超时工夫,定期删除某些键值对,也难以保障缓存占用的内存会被开释,会导致系统有内存透露的危险。