unsafe.SizeOf()
和reflect.Type.Size()
只返回傳遞值的大小,不遞歸遍歷數據結構並添加指向值的大小。
切片是相對簡單的結構:reflect.SliceHeader
,因爲我們知道它引用的背襯陣列,我們可以很容易地計算其大小「手動」,例如:
s := make([]int32, 1000)
fmt.Println("Size of []int32:", unsafe.Sizeof(s))
fmt.Println("Size of [1000]int32:", unsafe.Sizeof([1000]int32{}))
fmt.Println("Real size of s:", unsafe.Sizeof(s)+unsafe.Sizeof([1000]int32{}))
輸出(嘗試在Go Playground ):
Size of []int32: 12
Size of [1000]int32: 4000
Real size of s: 4012
地圖有很多更復雜的數據結構,我就不贅述了,但檢查出這個問題的答案+:Golang: computing the memory footprint (or byte length) of a map
如果你想要「真實」的數字,你可以利用Go的測試工具,它也可以執行內存基準測試。傳遞-benchmem
參數,基準函數內部僅要衡量其內存分配:(從getSlice()
當然getMap()
拆下正和打印話費)
func BenchmarkSlice100(b *testing.B) {
for i := 0; i < b.N; i++ { getSlice(100) }
}
func BenchmarkSlice1000(b *testing.B) {
for i := 0; i < b.N; i++ { getSlice(1000) }
}
func BenchmarkSlice10000(b *testing.B) {
for i := 0; i < b.N; i++ { getSlice(10000) }
}
func BenchmarkMap100(b *testing.B) {
for i := 0; i < b.N; i++ { getMap(100) }
}
func BenchmarkMap1000(b *testing.B) {
for i := 0; i < b.N; i++ { getMap(1000) }
}
func BenchmarkMap10000(b *testing.B) {
for i := 0; i < b.N; i++ { getMap(10000) }
}
與
運行
go test -bench . -benchmem
輸出是:
BenchmarkSlice100-4 3000000 471 ns/op 1792 B/op 1 allocs/op
BenchmarkSlice1000-4 300000 3944 ns/op 16384 B/op 1 allocs/op
BenchmarkSlice10000-4 50000 39293 ns/op 163840 B/op 1 allocs/op
BenchmarkMap100-4 200000 11651 ns/op 2843 B/op 9 allocs/op
BenchmarkMap1000-4 10000 111040 ns/op 41823 B/op 12 allocs/op
BenchmarkMap10000-4 1000 1152011 ns/op 315450 B/op 135 allocs/op
B/op
值告訴你每個操作分配了多少個字節。 allocs/op
表示每個操作有多少(不同的)內存分配。
在我的64位體系結構(其中int
的大小是8個字節)中,它指出具有2000個元素的片大小大約爲16 KB(與2000 * 8字節一致)。具有1000個對的地圖大約需要分配42 KB。
沒有_need_這樣做,因爲你可以計算所需的空間:切片的大小乘以每個元素的大小。對於地圖而言,由於某些內部區域無法訪問(例如散列衝突)而變得更加困難,但它基本上是相同的。 – Volker