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會作為緩存來存儲數據,即使按照超時時間,定期刪除某些鍵值對,也難以保證緩存佔用的內存會被釋放,會導致系統有內存泄漏的風險。