成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 語言中的map和內存泄漏

開發 后端
在 Go 中使用map時,我們需要了解map增長和收縮的一些重要特性。讓我們深入探討這一點,以防止可能導致內存泄漏的問題。

Map在內存中總是會增長;它不會收縮。因此,如果map導致了一些內存問題,你可以嘗試不同的選項,比如強制 Go 重新創建map或使用指針。

在 Go 中使用map時,我們需要了解map增長和收縮的一些重要特性。讓我們深入探討這一點,以防止可能導致內存泄漏的問題。

首先,為了查看這個問題的一個具體例子,讓我們設計一個場景,在這個場景中我們將使用以下map:

m := make(map[int][128]byte)

每個 m 的值都是一個包含 128 字節的數組。我們將執行以下操作:

  • 分配一個空的map。
  • 添加 100 萬個元素。
  • 刪除所有元素,并運行垃圾回收(GC)。

在每個步驟之后,我們希望打印堆的大?。ㄊ褂靡粋€ printAlloc 實用函數)。這將展示這個示例在內存方面的行為方式:

func main() {
    n := 1_000_000
    m := make(map[int][128]byte)
    printAlloc()

    for i := 0; i < n; i++ { // Adds 1 million elements
        m[i] = [128]byte{}
    }
    printAlloc()

    for i := 0; i < n; i++ { // Deletes 1 million elements
        delete(m, i)
    }

    runtime.GC() // Triggers a manual GC
    printAlloc()
    runtime.KeepAlive(m) // Keeps a reference to m so that the map isn’t collected
}

func printAlloc() {
    var m runtime.MemStats
    runtime.ReadMemStats(&m)
    fmt.Printf("%d KB\n", m.Alloc/1024)
}

我們分配一個空的map,添加 100 萬個元素,刪除 100 萬個元素,然后運行垃圾回收。我們還確保使用 runtime.KeepAlive 保持對map的引用,以防止map被收集。讓我們運行這個示例:

0 MB   <-- After m is allocated
461 MB <-- After we add 1 million elements
293 MB <-- After we remove 1 million elements

我們觀察到了什么?起初,堆大小很小。然后,在將 100 萬個元素添加到map后,它顯著增長了。但是,如果我們期望在刪除所有元素后堆大小會減小,這并不是 Go 中map的工作方式。最后,盡管 GC 已經收集了所有元素,但堆大小仍然是 293 MB。因此,內存縮小了,但并非我們可能預期的方式。這其中的原理是什么?我們需要深入了解一下 Go 中map的工作原理。

map提供了一個無序的鍵值對集合,其中所有的鍵都是唯一的。在 Go 中,map基于哈希表數據結構:一個數組,其中每個元素都是指向鍵值對存儲桶的指針,如圖1所示。

圖1 — 哈希表示例,重點關注存儲桶 0。

每個存儲桶都是一個固定大小的數組,包含八個元素。如果要將元素插入已經滿了的存儲桶(即存儲桶溢出),Go 會創建另一個包含八個元素的存儲桶,并將前一個存儲桶鏈接到它上。圖2顯示了一個例子:

圖2 — 如果存儲桶溢出,Go 會分配一個新的存儲桶,并將前一個存儲桶鏈接到它上。

在底層,Go 中的map是指向 runtime.hmap 結構體的指針。該結構體包含多個字段,其中包括一個 B 字段,表示map中存儲桶的數量:

type hmap struct {
    B uint8 // log_2 of # of buckets
            // (can hold up to loadFactor * 2^B items)
    // ...
}

在添加了100萬個元素之后,B 的值等于18,這意味著有 21? = 262,144 個存儲桶。當我們刪除了100萬個元素后,B 的值是多少呢?仍然是18。因此,map仍然包含相同數量的存儲桶。

原因在于map中存儲桶的數量是不可縮減的。因此,從map中刪除元素不會影響現有存儲桶的數量;它只是將存儲桶中的槽清零。map只能增長并擁有更多的存儲桶;它永遠不會縮小。

在先前的示例中,我們從461 MB減少到了293 MB,因為元素被收集,但運行垃圾回收并沒有影響map本身。即使額外存儲桶的數量(因為溢出而創建的存儲桶)也保持不變。

讓我們退一步,討論map無法縮小的情況何時可能成為問題。想象一下使用 map[int][128]byte 來構建緩存。這個map以每個客戶ID(int)為鍵,保存一個長度為128字節的序列?,F在,假設我們想保存最近的1000位客戶。map的大小將保持不變,所以我們不必擔心map無法縮小的問題。

但是,假設我們想要存儲一小時的數據。同時,我們的公司決定在黑色星期五進行大促銷:在一個小時內,我們可能會有數百萬的客戶連接到我們的系統。但是在黑色星期五之后的幾天,我們的map將包含與高峰期相同數量的存儲桶。這就解釋了為什么在這種情況下我們可能會遇到內存消耗高卻不會顯著減少的情況。

如果我們不想手動重啟服務來清理map消耗的內存量,有哪些解決方案?一種解決方案可以是定期重新創建當前map的副本。例如,每小時我們可以構建一個新map,復制所有元素,并釋放先前的map。這種選擇的主要缺點是,在復制后直到下一次垃圾回收之前,我們可能會在短時間內消耗兩倍于當前內存。

另一種解決方案是將map類型更改為存儲數組指針:map[int]*[128]byte。這并沒有解決我們會有大量存儲桶的問題;然而,每個存儲桶條目將為值保留指針的大小,而不是128字節(64位系統上為8字節,32位系統上為4字節)。

回到原始場景,讓我們比較每種map類型在每個步驟后的內存消耗。以下表格顯示了比較。

Step

map[int][128]byte

map[int]*[128]byte

分配一個空的 map

0 MB

0 MB

添加100萬個元素

461 MB

182 MB

刪除所有元素并運行GC

293 MB

38 MB

正如我們所看到的,在刪除所有元素后,使用 map[int]*[128]byte 類型所需的內存量明顯較少。此外,在這種情況下,由于一些優化措施以減少內存消耗,高峰時期所需的內存量也較少顯著。

注意:如果鍵或值超過128字節,Go 將不會直接將其存儲在map存儲桶中。相反,Go 將存儲用于引用鍵或值的指針。

結論

正如我們所見,向map添加 n 個元素,然后刪除所有元素意味著在內存中保持相同數量的存儲桶。因此,我們必須記住,由于 Go map只能增長,因此其內存消耗也會隨之增加。它沒有自動化的策略來縮小。如果這導致內存消耗過高,我們可以嘗試不同的選項,比如強制 Go 重新創建map或使用指針來檢查是否可以進行優化。

責任編輯:趙寧寧 來源: 技術的游戲
相關推薦

2012-06-15 09:56:40

2023-11-30 08:09:02

Go語言

2022-10-10 11:37:14

Gomap內存

2023-12-30 18:35:37

Go識別應用程序

2014-01-14 09:10:53

GoHTTP內存泄漏

2024-04-07 11:33:02

Go逃逸分析

2021-07-15 23:18:48

Go語言并發

2023-12-21 07:09:32

Go語言任務

2023-10-09 07:14:42

panicGo語言

2022-07-19 12:25:29

Go

2021-06-08 07:45:44

Go語言優化

2023-07-29 15:03:29

2023-01-12 08:52:50

GoroutinesGo語言

2025-05-30 01:55:00

go語言Redis

2023-12-25 09:58:25

sync包Go編程

2024-05-10 08:36:40

Go語言對象

2024-12-05 08:58:47

2025-03-27 00:45:00

2024-01-08 07:02:48

數據設計模式

2021-07-13 06:44:04

Go語言數組
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产高清视频 | 国产一区中文 | 97avcc| 中文字幕在线播放第一页 | 久久精品91| av片在线播放 | 97精品久久| 中文字幕视频免费 | 亚洲天堂一区二区 | 久久久蜜桃 | 一区在线视频 | 欧美日韩在线一区二区 | 日本羞羞影院 | 99爱视频| 国产精品高清一区二区 | 91亚洲国产成人精品一区二三 | 欧美国产一区二区 | 91亚洲国产成人久久精品网站 | 美女视频一区 | 成人一区二区三区在线观看 | 国产在线一级片 | 成人av在线播放 | 久久久新视频 | 天天操天天操 | 欧美在线一区二区三区 | 蜜桃av一区二区三区 | 久久久精品一区 | 国产精品美女久久久久久免费 | 国产精品乱码一区二三区小蝌蚪 | 91视频在线看| 最新国产精品精品视频 | 一区二区精品 | 日韩欧美在 | 亚洲精品久久久久久久久久久 | 91精品国产手机 | 欧美在线观看一区 | 久久精品免费观看 | 日韩中文字幕一区二区 | 国产欧美一区二区三区久久手机版 | 精品一区二区电影 | 欧美一级视频免费看 |