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

Go:Map 和 內存泄露

開發 前端
在 Go 中使用 map 時,我們需要了解 map 如何增長和收縮的一些重要特征。讓我們深入研究一下,以防止可能導致內存泄漏的問題。

大家好,我是程序員幽鬼。分享一篇關于 map 和“內存泄露”的文章。

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

在 Go 中使用 map 時,我們需要了解 map 如何增長和收縮的一些重要特征。讓我們深入研究一下,以防止可能導致內存泄漏的問題。

首先,要查看此問題的具體示例,讓我們設計一個場景,其中我們將使用以下 map:

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

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

在每一步之后,我們都要打印堆的大小(使用printAlloc實用程序函數)。它向我們展示了此示例的內存行為:

() {
n := 1_000_000
m := make([][128])
printAlloc()

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

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
}

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

我們分配一個空 map,添加 100 萬個元素,刪除 100 萬個元素,然后運行 GC。我們還確保使用 [1] 保持對 map 的引用,這樣 map 就不會被垃圾收集了。讓我們運行這個示例:

0 MB <-- m 被分配后
461 MB <-- 我們增加 100 萬個元素后
293 MB <-- 我們刪除 100 萬個元素后

我們能觀察到什么?首先,堆大小是最小的。然后,在向 map 添加了100萬個元素后,它會顯著增長。但是,如果我們預期在刪除所有元素后堆大小會減小,那么這并不是 map 在Go中的工作方式。最后,即使 GC 已經收集了所有元素,堆大小仍然是 293 MB。因此,內存雖然縮小了,但并不像我們預期的那樣。原因是什么?我們需要深入研究 map 在Go中的工作原理。

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

圖片

圖1— 一個哈希表示例,重點放在 bucket 0 上。

每個 bucket 是一個由八個元素組成的固定大小數組。如果插入到已經滿了的 bucket 中(bucket 溢出),Go 會創建另一個包含八個元素的 buckets,并將前一個元素鏈接到該bucket。圖 2 顯示了一個示例:

圖片

圖 2 — 如果 bucket 溢出,Go 會分配一個新的 bucket,并將前一個 bucket 鏈接到該bucket。

在底層,Go map 是指向 [2] 結構體的指針。此結構體包含多個字段,包括一個 B 字段,用于提供 map 中的存儲桶數:

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

添加 100 萬個元素后,B 的值等于 18,即 21? = 262144 個桶。當我們移除 100 萬個元素時,B 的值是多少?仍然是18。因此,map 仍然包含相同數量的桶。

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

在前一個示例中,我們從 461MB 到 293MB,因為垃圾收集了元素,但運行 GC 不會影響 map 本身。即使額外的存儲桶數(由于溢出而創建的存儲桶)也保持不變。

讓我們后退一步,討論 map 不能收縮的事實何時會成為問題。想象一下,使用 map[int][128]byte 構建緩存。此 map 包含每個客戶 ID(int 類型),一個 128 字節的序列。現在,假設我們想保留最后 1000 名客戶。map 大小將保持不變,因此我們不必擔心 map 無法收縮的事實。

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

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

另一個解決方案是更改 map 類型以存儲數組指針:map[int]*[128]byte。這并不能解決我們將擁有大量桶的事實;然而,每個 bucket 條目將為該值保留指針的大小,而不是 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 bucket 中。相反,Go 存儲一個指針來引用鍵或值。

結論

正如我們所看到的,將 n 個元素添加到 map 中,然后刪除所有元素意味著在內存中保留相同數量的 bucket。因此,我們必須記住,因為 Go map 只能增加大小,所以它的內存消耗也會增加。沒有自動化的策略來縮小它。如果這導致高內存消耗,我們可以嘗試不同的選項,例如強制 Go 重新創建 map 或使用指針檢查是否可以優化。

原文鏈接:https://teivah.medium.com/maps-and-memory-leaks-in-go-a85ebe6e7e69。

參考資料

[1]runtime.KeepAlive: https://pkg.go.dev/runtime#KeepAlive

[2]runtime.hmap: https://github.com/golang/go/blob/f983a9340d5660a9655b63a371966b5df69be8c5/src/runtime/map.go#L116

責任編輯:武曉燕 來源: 幽鬼
相關推薦

2023-11-21 15:46:13

Go內存泄漏

2010-08-10 10:00:57

Flex內存

2010-06-02 13:00:43

Linux 內存監控

2022-06-27 11:20:13

工具內存GO

2021-10-08 11:05:00

Go 切片內存

2022-02-07 08:55:57

Go程序代碼

2010-07-29 14:08:05

Flex內存泄露

2017-12-11 11:00:27

內存泄露判斷

2013-12-17 16:01:02

iOSXcodeInstruments

2013-04-09 14:49:18

Linux內存統計內存泄露

2012-06-15 09:56:40

2013-08-07 10:07:07

Handler內存泄露

2017-05-04 16:07:11

Tomcat內存泄露

2023-03-03 12:37:50

JavaJVM內存溢出

2011-07-20 17:04:43

Objective-C 內存 內存泄露

2012-04-11 13:46:33

ibmdw

2023-01-10 09:18:37

Go內存分配逃逸

2013-12-23 09:25:21

2017-10-26 08:43:18

JavaScript內存處理

2010-09-25 11:32:24

Java內存泄漏
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产91精品久久久久久久网曝门 | 日韩欧美在线播放 | 免费一区 | 色资源在线 | 亚洲视频在线免费 | 激情国产在线 | 欧美日韩在线一区二区 | 国产专区在线 | 国产精品国产三级国产aⅴ中文 | 精国产品一区二区三区四季综 | 午夜激情免费 | 国产精品亚洲欧美日韩一区在线 | 免费成人av | 97超碰成人 | 日韩精品一区二 | 亚洲国产欧美精品 | 亚洲性网| www.国产.com| 日本一二区视频 | 欧美久久久电影 | 国产精品影视在线观看 | 欧美国产日韩在线观看成人 | 91精品在线观看入口 | 欧美成年黄网站色视频 | 久久精品91久久久久久再现 | 精品影视| 久久久激情视频 | 久久精品久久久久久 | 久久av一区二区 | 波多野结衣一区二区三区 | 亚洲免费精品 | 日本不卡免费新一二三区 | 国产中文视频 | 欧美一级片 | 一级免费黄色 | 精品欧美一区二区在线观看欧美熟 | 成人在线免费看 | 欧美日韩一区二区三区不卡视频 | 欧美午夜视频 | 亚洲精品在线视频 | 亚洲精品乱码久久久久久黑人 |