博客 / 詳情

返回

【golang】go語言中map導致的內存泄漏問題

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

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.