GO物件對齊 怎麼輕鬆降低記憶體占用

2021-09-29 14:58:55 字數 2360 閱讀 1487

我們先看下面的**

var a =

struct

var b =

struct

看起來這兩個變數包含的字段一模一樣的,都是兩個byte和乙個int,那麼他們的大小相同嗎?

我們不妨使用reflect包檢查一下,**如下圖

typea := reflect.

typeof

(a)typeb := reflect.

typeof

(b)fmt.

println

("a size"

, typea.

size()

)fmt.

println

("b size"

, typeb.

size()

)

返回結果

奇也怪哉,我們只是調換了下字段順序而已,為什麼會有這樣的差異?

為了解釋這個問題,我們需要理解一點-對齊

什麼是對齊呢,就是說記憶體布局中,兩個字段之間不一定是緊緊貼著的,而是可能會留下乙個空檔,這是因為我們的作業系統在獲取值的時候,並不是像我們想象中一樣乙個位元組乙個位元組的獲取,而是可能按照2,4,8個位元組(不同系統不一樣)獲取乙個塊。

那麼我們不妨想象一下, 假設乙個int被放置在1的位置,占用了1,2,3,4個記憶體塊,而某作業系統是按照4個位元組開始獲取,他會怎麼得到這個int變數呢?

他會首先獲取到0 1 2 3四個位元組的塊,然後再獲取4 5 6 7的塊,最後剪下拼貼成這個int;反過來如果int直接就位於4這個起點,系統就只需要1次獲取,中間的花銷差距可以想象。

更何況,很多作業系統甚至不支援這種操作,也就是說如果你索取上述這麼個變數,系統就罷工了

為了應對上述的情形,go於是搬出了型別對齊保證這麼個概念,也就是說go對於若干種型別,都設定了他的對齊保證,確保該型別儲存的起始位址是這個指定值的倍數,想想看,對於上面int的處理,如果我們能保證int永遠從4的倍數開始,不就可以很好地解決這個問題嗎?

型別對齊保證解決了這個「無法或者不能高效獲取值」的問題,但是這樣卻引入了乙個新的問題,我們知道go中結構體的記憶體布局是依賴於欄位的,也就是說字段宣告的時候順序是abc,那麼記憶體布局中就會是abc。

試想一下,如果b的「型別對齊保證」是8位元組,而a的大小只有1位元組(比方說是boolean),那麼ab之間就得空出7個位元組,因此占用了16個位元組(而不是9位元組)。

問題還不僅僅如此,比方說對於剛剛的問題,我們如果嘗試改為ba順序,我們會發現結果仍然是16位元組,這是因為結構體本身也有型別對齊保證(一般等於欄位的最大型別對齊保證),而a填充完之後,結構體因為自身型別對齊保證是8位元組,於是會乖乖的在後面空出七個位元組,於是我們並沒有起到效果。

總的來說,我們會發現欄位的順序其實會影響到記憶體的大小,那麼我們有沒有什麼比較好的辦法去處理來提高記憶體使用呢?

很簡單,我們可以將字段從占用位元組數大到小排序,就可以儘量減少記憶體空洞了。

如下圖所示

可以看到在當前的布局下,第一層和第三層並沒有得到很好地利用,如果我們調整順序,就可以實現下面的效果

當然一切的前提在於我們需要知道該型別的占用大小和型別對齊大小,我們可以用reflect.typeof(t).align()來獲取一般型別對齊大小,用reflect.typeof(t).fieldalign()來獲取字段型別對齊大小,在官方編譯器中,二者應該是一致的,我們還可以用reflect.typeof(t).size()來獲取大小

當然其實我們也可以根據下述**查詢

type                                 size in bytes

byte

,uint8

,int8

1uint16

,int16

2uint32

,int32

,float32

4uint64

,int64

,float64

,complex64

8complex128

16

初次之外,對於結構體來說,其對齊保證大小是字段的對齊保證的最大值,同時至少為1(即便是空的)

而對於陣列來說,對齊大小等同於其中乙個元素的對齊保證大小

GO 記憶體對齊

之前遇到過這樣乙個情況 發現問題的結構體並不長這樣,不過為了引出問題,改了一下 type test structfunc main fmt.printf d unsafe.sizeof t 建立乙個結構體,檢視一下其記憶體占用.看結果前先簡單算一下 這麼算下來的話,test結構體占用應該是 1 4 ...

Go記憶體對齊

fmt.println unsafe.sizeof int64 0 8 type sizeofa struct unsafe.sizeof sizeofa 8 type sizeofc struct unsafe.sizeof sizeofc 8 unsafe.alignof sizeofc 4 結...

GO語言 記憶體對齊

32位系統,一次可以取32位資料,也就是4位元組,64位是8位元組,即32為作業系統中記憶體是4位元組對齊,而對於64為作業系統是8位元組對齊 記憶體對齊的目的是為了能夠快速的訪問記憶體進行資料訪問,但是會損耗記憶體,即空間換時間 首先 package main import fmt reflect...