Go語言在處理切片和陣列時,對於長度為100k的切片所使用的記憶體要比長度為100k的陣列要少。這是因為切片在底層實作中採用了指標和長度的組合,而陣列則需要連續的記憶體空間來儲存資料。由於切片的長度是可變的,所以可以動態地分配和釋放內存,而數組則需要在聲明時就指定固定的長度。因此,當處理大量資料時,使用切片可以更有效率地利用記憶體空間,減少記憶體的佔用。這也是Go語言在處理大規模資料時的一個優勢之一。
考慮以下程式碼,我分配了 4000 個數組,每個數組長度為 100k:
parentmap := make(map[int][100_000]int) for i := 0; i < 4000; i++ { parentmap[i] = [100_000]int{} time.sleep(3 * time.millisecond) }
如果我在本地運行該程式並分析其記憶體使用情況,它會開始使用 >2gb 記憶體。
現在,如果我們稍微更改程式碼以使用陣列切片(但長度也為 100k),如下所示:
parentMap := make(map[int][]int) for i := 0; i < 4000; i++ { parentMap[i] = make([]int, 100_000) time.Sleep(3 * time.Millisecond) }
在我的機器上,記憶體峰值約為 73mb。 這是為什麼?
我認為這兩個片段將使用大致相同的內存,原因如下:
parentmap
的值。 go 這樣做是因為如果它在堆疊上分配這些值,那麼一旦當前函數超出範圍,parentmap
的值就會全部清除。 我讀:https://go.dev/blog/slices-intro。但找不到解釋這一點的實作細節。
有切片的版本可能會受益於延遲分配。沒有任何東西會嘗試寫入這些片之一的資料緩衝區,因此作業系統可以自由地不為這些緩衝區實際分配內存,直到確實嘗試寫入。 (作業系統也可以延遲對緩衝區進行零初始化,因此不會強制分配。)
同時,帶有陣列的版本需要將陣列實際複製到映射中,這意味著實際執行寫入。即使寫入的值全為零,它們仍然是寫入,因此作業系統必須實際為要寫入的資料分配記憶體。
嘗試將資料寫入這些切片,切片版本也應該佔用千兆位元組的記憶體。 (我認為每頁記憶體一個值應該足夠了,但是用 1
s 填充切片可能會更容易。)
以上是為什麼 Go 對於長度為 100k 的切片使用的記憶體比長度為 100k 的陣列少?的詳細內容。更多資訊請關注PHP中文網其他相關文章!