<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
除非您正在對服務進行原型設計,否則您可能會關心應用程式的記憶體使用情況。記憶體佔用更小,基礎設施成本降低,擴充套件變得更容易/延遲。
儘管 Go 以不消耗大量記憶體而聞名,但仍有一些方法可以進一步減少消耗。其中一些需要大量重構,但很多都很容易做到。
陣列是具有連續記憶體的相同型別的集合。陣列型別定義指定長度和元素型別。陣列的主要問題是它們的大小是固定的——它們不能調整大小,因為陣列的長度是它們型別的一部分。
與陣列型別不同,切片型別沒有指定長度。切片的宣告方式與陣列相同,但沒有元素計數。
切片是陣列的包裝器,它們不擁有任何資料——它們是對陣列的參照。它們由指向陣列的指標、段的長度及其容量(底層陣列中的元素數)組成。
當您追加到一個沒有新值容量的切片時 - 會建立一個具有更大容量的新陣列,並將當前陣列中的值複製到新陣列中。這會導致不必要的分配和 CPU 週期。
為了更好地理解這一點,讓我們看一下以下程式碼段:
func main() { var ints []int for i := 0; i < 5; i++ { ints = append(ints, i) fmt.Printf("Address: %p, Length: %d, Capacity: %d, Values: %vn", ints, len(ints), cap(ints), ints) } }
輸出如下:
Address: 0xc0000160c8, Length: 1, Capacity: 1, Values: [0]
Address: 0xc0000160f0, Length: 2, Capacity: 2, Values: [0 1]
Address: 0xc00001e080, Length: 3, Capacity: 4, Values: [0 1 2]
Address: 0xc00001e080, Length: 4, Capacity: 4, Values: [0 1 2 3]
Address: 0xc00001a140, Length: 5, Capacity: 8, Values: [0 1 2 3 4]
檢視輸出,我們可以得出結論,無論何時必須增加容量(增加 2 倍),都必須建立一個新的底層陣列(新的記憶體地址)並將值複製到新陣列中。
有趣的事實是,容量增長的因素曾經是容量 <1024 的 2 倍,以及 >= 1024 的 1.25 倍。從 Go 1.18 開始,這已經變得更加線性。
name time/op Append-10 3.81ns ± 0% PreallocAssign-10 0.41ns ± 0% name alloc/op Append-10 45.0B ± 0% PreallocAssign-10 8.00B ± 0% name allocs/op Append-10 0.00 PreallocAssign-10 0.00
檢視上述基準,我們可以得出結論,將值分配給預分配的切片和將值附加到切片之間存在很大差異。
兩個 linter 有助於預分配切片:
您之前可能沒有想到這一點,但結構中欄位的順序對記憶體消耗很重要。
以下面的結構為例:
type Post struct { IsDraft bool // 1 byte Title string // 16 bytes ID int64 // 8 bytes Description string // 16 bytes IsDeleted bool // 1 byte Author string // 16 bytes CreatedAt time.Time // 24 bytes } func main(){ p := Post{} fmt.Println(unsafe.Sizeof(p)) }
上述函數的輸出為 96(位元組),而所有欄位相加為 82 位元組。額外的 14 個位元組來自哪裡?
現代 64 位 CPU 以 64 位(8 位元組)塊的形式獲取資料。如果我們有一個較舊的 32 位 CPU,它將執行 32 位(4 位元組)的塊。
第一個週期佔用 8 個位元組,IsDraft
欄位佔用 1 個位元組,並有 7 個未使用位元組。它不能佔據一個欄位的“一半”。
第二和第三個迴圈取 Title
字串,第四個迴圈取 ID
,依此類推。再次使用 IsDeleted
欄位,它需要 1 個位元組並有 7 個未使用的位元組。
真正重要的是按欄位的大小從上到下對欄位進行排序。對上述結構進行排序,大小減少到 88 個位元組。最後兩個欄位 IsDraft
和 IsDeleted
被放在同一個塊中,從而將未使用的位元組數從 14 (2x7) 減少到 6 (1 x 6),在此過程中節省了 8 個位元組。
type Post struct { CreatedAt time.Time // 24 bytes Title string // 16 bytes Description string // 16 bytes Author string // 16 bytes ID int64 // 8 bytes IsDeleted bool // 1 byte } func main(){ p := Post{} fmt.Println(unsafe.Sizeof(p)) }
在 64 位架構上佔用 <8 位元組的 Go 型別:
無需手動檢查結構並按大小對其進行排序,而是使用 linter 找到這些結構並(用於)報告“正確”排序。
要安裝和執行 fieldalignment:
go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest fieldalignment -fix <package_path>
在上面的程式碼中使用 govet/fieldalignment:
fieldalignment: struct of size 96 could be 88 (govet)
Go 沒有內建集合,通常使用 map[string]bool{}
來表示集合。儘管它更具可讀性,這一點非常重要,但將其作為一個集合使用是錯誤的,因為它有兩種狀態(假/真),並且與空結構相比使用了額外的記憶體。
空結構體 (struct{}
) 是沒有額外欄位的結構體型別,佔用零位元組儲存空間。
我不建議這樣做,除非您的 map/set 包含大量值並且您需要獲得額外的記憶體或者您正在為低記憶體平臺進行開發。
使用 100 000 000 次寫入地圖的極端範例:
func BenchmarkBool(b *testing.B) { m := make(map[uint]bool) for i := uint(0); i < 100_000_000; i++ { m[i] = true } } func BenchmarkEmptyStruct(b *testing.B) { m := make(map[uint]struct{}) for i := uint(0); i < 100_000_000; i++ { m[i] = struct{}{} } }
得到以下結果,在整個執行過程中非常一致:
name time/op Bool 12.4s ± 0% EmptyStruct 12.0s ± 0% name alloc/op Bool 3.78GB ± 0% EmptyStruct 3.43GB ± 0% name allocs/op Bool 3.91M ± 0% EmptyStruct 3.90M ± 0%
使用這些數位,我們可以得出結論,使用空結構對映的寫入速度提高了 3.2%,分配的記憶體減少了 10%。
此外,使用 map[type]struct{}
是實現集合的正確解決方法,因為每個鍵都有一個值。使用 map[type]bool
,每個鍵都有兩個可能的值,這不是一個集合,如果目標是建立一個集合,則可能會被誤用。
然而,可讀性大多數時候比(可忽略的)記憶體改進更重要。與空結構體相比,使用布林值更容易掌握查詢:
m := make(map[string]bool{}) if m["key"]{ // Do something } v := make(map[string]struct{}{}) if _, ok := v["key"]; ok{ // Do something }
參考連結:Easy memory-saving tricks in Go | Emir Ribic (ribice.ba)
以上就是Golang 記憶體管理簡單技巧詳解的詳細內容,更多關於Golang 記憶體管理的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45