Go的類型變量在內存中佈局中的一個奇怪問題。

研究Go的類型變量,在內存中的佈局的時候,遇到了一個怪異的問題(備註:筆者機器是64位系統,這很重要)。html

package main

import "fmt"

func main() {
	a1 := 1
	a2 := 2

	fmt.Printf("%p\n", &a1)
	fmt.Printf("%p\n", &a2)
	fmt.Println()

	b1 := "1"
	b2 := "2"

	fmt.Printf("%p\n", &b1)
	fmt.Printf("%p\n", &b2)
	fmt.Println()


	c1 := []int{1}
	c2 := []int{2}

	fmt.Printf("%p\n", &c1)
	fmt.Printf("%p\n", &c2)
}

結果git

0xc420070030
0xc420070038

0xc420070050
0xc420070060

0xc42007a000
0xc42007a020

根據結果,能夠明顯的看出,int類型佔8個byte,string類型佔16byte,因此,按照Go語言的設計官方博客說明),slice應該佔24byte纔對,可是事實倒是佔用了32byte的空間。github

翻了不少資料,最後在雨痕的Go源碼分析第四章內存分配中找到了答案。golang

分配器將其管理的內存塊分爲兩種:架構

  • span: 由多個地址連續的頁(page)組成的大塊內存
  • object: 將 span 按特定大小切分紅多個小塊,每一個小塊可存儲一個對象

……函數

用於存儲對象的 object,按 8 字節倍數分爲 n 種。好比說,大小爲 24 的 object 可用來存儲 範圍在 17 ~ 24 字節的對象。這種方式雖然會形成一些內存浪費,但分配器只需面對有限 的幾種規格(size class)小塊內存,優化了分配和複用管理策略。源碼分析

由於slice須要24byte,根據Go的內存分配策略,分到32byte。佈局

雨痕並無在書中指出優化

8 字節倍數分爲 n 種spa

代碼實如今哪裏。

我在這裏補充下,在$GOROOT/src/runtime/msize.go的函數initSizes找到這個實現策略。

// Initialize the size_to_class tables.
	nextsize := 0
	for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ {
		for ; nextsize < 1024 && nextsize <= int(class_to_size[sizeclass]); nextsize += 8 {
			size_to_class8[nextsize/8] = int8(sizeclass)
		}
		if nextsize >= 1024 {
			for ; nextsize <= int(class_to_size[sizeclass]); nextsize += 128 {
				size_to_class128[(nextsize-1024)/128] = int8(sizeclass)
			}
		}
	}

更多架構、PHP、GO相關踩坑實踐技巧請關注個人公衆號:PHP架構師

相關文章
相關標籤/搜索