中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何給Golang map做GC

發布時間:2021-08-18 09:07:56 來源:億速云 閱讀:224 作者:小新 欄目:編程語言

這篇文章主要為大家展示了“如何給Golang map做GC”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“如何給Golang map做GC”這篇文章吧。

                           

Golang 中的 map 結構,在刪除鍵值對的時候,并不會真正的刪除,而是標記。那么隨著鍵值對越來越多,會不會造成大量內存浪費?

首先答案是會的,很有可能導致 OOM,而且針對這個還有一個討論:github.com/golang/go/issues/20135。大致的意思就是在很大的 map 中,delete 操作沒有真正釋放內存而可能導致內存 OOM。

所以一般的做法:就是 重建map。而 go-zero 中內置了 safemap 的容器組件。safemap 在一定程度上可以避免這種情況發生。

那首先我們看看 go 原生提供的 map 是怎么刪除的?

原生map刪除

1  package main
2
3  func main() {
4      m := make(map[int]string, 9)
5      m[1] = "hello"
6      m[2] = "world"
7      m[3] = "go"
8
9      v, ok := m[1]
10     _, _ = fn(v, ok)
11
12     delete(m, 1)
13  }
14
15 func fn(v string, ok bool) (string, bool) {
16     return v, ok
17 }

測試代碼如上,我們可以通過 go tool compile -S -N -l testmap.go | grep "CALL"

0x0071 00113 (test/testmap.go:4)        CALL    runtime.makemap(SB)
0x0099 00153 (test/testmap.go:5)        CALL    runtime.mapassign_fast64(SB)
0x00ea 00234 (test/testmap.go:6)        CALL    runtime.mapassign_fast64(SB)
0x013b 00315 (test/testmap.go:7)        CALL    runtime.mapassign_fast64(SB)
0x0194 00404 (test/testmap.go:9)        CALL    runtime.mapaccess2_fast64(SB)
0x01f1 00497 (test/testmap.go:10)       CALL    "".fn(SB)
0x0214 00532 (test/testmap.go:12)       CALL    runtime.mapdelete_fast64(SB)
0x0230 00560 (test/testmap.go:7)        CALL    runtime.gcWriteBarrier(SB)
0x0241 00577 (test/testmap.go:6)        CALL    runtime.gcWriteBarrier(SB)
0x0252 00594 (test/testmap.go:5)        CALL    runtime.gcWriteBarrier(SB)
0x025c 00604 (test/testmap.go:3)        CALL    runtime.morestack_noctxt(SB)

執行第12行的 delete,實際執行的是 runtime.mapdelete_fast64

這些函數的參數類型是具體的 int64mapdelete_fast64 跟原始的 delete 操作一樣的,所以我們來看看 mapdelete

mapdelete

長圖預警!!!

如何給Golang map做GC

大致代碼分析如上,具體代碼就留給大家去閱讀了。其實大致過程:

  1. 寫保護,防止并發寫

  2. 查詢要刪除的 key 是否存在

  3. 存在則對其標志做刪除標記

  4. count--

所以你在大面積刪除 key ,實際 map 存儲的 key 是不會刪除的,只是標記當前的key狀態為 empty

其實出發點,和 mysql 的標記刪除類似,防止后續會有相同的 key 插入,省去了擴縮容的操作。

但是這個對有些場景是不妥的,如果開發者在未來時間內都不會再插入相同的 key ,很可能會導致 OOM

所以針對以上情況,go-zero 開發了 safemap 。下面我們看看 safemap 是如何避免這個問題的?

safemap

直接從操作 safemap 中分析為什么要這么設計:

如何給Golang map做GC

  1. 預設一個 刪除閾值,如果觸發會放到一個新預設好的 newmap

  2. 兩個 map 是一個整體,所以 key 只能留一份

所以為什么要設置兩個 map 就很清楚了:

  1. dirtyOld 作為存儲主體,如果 delete 操作達到閾值,則會觸發遷移。

  2. dirtyNew 作為暫存體,會在到達閾值時,存放部分 key/value

所以在遷移操作時,我們需要做的就是:將原先的 dirtyOld 清空,存儲的 key/value 通過 for-range 重新存儲到 dirtyNew,然后將 dirtyNew 指向 dirtyOld

可能會有疑問:不是說 key/value 沒有刪除嗎,只是標記了 tophash=empty

其實在 for-range 過程中,會過濾掉 tophash <= emptyOne 的 key

這樣就實現了不需要的 key 不會被加入到 dirtyNew,進而不會影響 dirtyOld

如何給Golang map做GC

這其實也就是垃圾回收的年老代和新生代的概念。

以上是“如何給Golang map做GC”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

静宁县| 陈巴尔虎旗| 紫金县| 高邑县| 台北县| 比如县| 南乐县| 静安区| 耿马| 镇雄县| 固镇县| 武川县| 循化| 洞口县| 五寨县| 治县。| 左贡县| 新营市| 北票市| 中牟县| 平果县| 镇安县| 略阳县| 康保县| 满洲里市| 泰州市| 绥宁县| 沂南县| 通山县| 永州市| 滁州市| 达拉特旗| 长岭县| 新巴尔虎右旗| 新干县| 崇阳县| 大连市| 武胜县| 宁海县| 武鸣县| 桐庐县|