go語言對齊技巧 對稱go怎么玩

golang 結構體 字節(jié)對齊是怎么樣的

用golang解析二進制協(xié)議時,其實沒必要管結構體的字段的對齊規(guī)則,何況語言規(guī)范也沒有規(guī)定如何對齊,也就是沒有規(guī)則。用encoding/binary.Read函數(shù)直接讀入struct里就行,struct就像c那樣寫

公司主營業(yè)務:成都網(wǎng)站制作、成都網(wǎng)站設計、移動網(wǎng)站開發(fā)等業(yè)務。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)公司是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)公司推出秦淮免費做網(wǎng)站回饋大家。

type Data struct {

Size, MsgType uint16

Sequence uint32

// ...

}

golang編譯器加不加padding,Read都能正常工作,runtime知道Data的布局的,不像C直接做cast所以要知道怎樣對齊。

用unsafe.Alignof可以知道每個field的對齊長度,但沒必要用到。

package main

/*

#include stdint.h

#pragma pack(push, 1)

typedef struct {

uint16_t size;

uint16_t msgtype;

uint32_t sequnce;

uint8_t data1;

uint32_t data2;

uint16_t data3;

} mydata;

#pragma pack(pop)

mydata foo = {

1, 2, 3, 4, 5, 6,

};

int size() {

return sizeof(mydata);

}

*/

import "C"

import (

"bytes"

"encoding/binary"

"fmt"

"log"

"unsafe"

)

func main() {

bs := C.GoBytes(unsafe.Pointer(C.foo), C.size())

fmt.Printf("len %d data %v\n", len(bs), bs)

var data struct {

Size, Msytype uint16

Sequence uint32

Data1 uint8

Data2 uint32

Data3 uint16

}

err := binary.Read(bytes.NewReader(bs), binary.LittleEndian, data)

if err != nil {

log.Fatal(err)

}

fmt.Printf("%v\n", data) // {1 2 3 4 5 6}

buf := new(bytes.Buffer)

binary.Write(buf, binary.BigEndian, data)

fmt.Printf("%d %v\n", buf.Len(), buf.Bytes()) // 15 [0 1 0 2 0 0 0 3 4 0 0 0 5 0 6]

}

golang內(nèi)存對齊

`

`

計算機結構中可能會要求內(nèi)存地址進行對齊;也就是說,一個變量的地址是一個因子的倍數(shù)。例如

`

`

在golang上,開發(fā)者有義務使64位字長的數(shù)據(jù)原子訪問是64位(8字節(jié))對齊的。 在 全局變量,結構體和切片的第一個字長數(shù)據(jù)可以被認為是64位對齊,如果是嵌套的結構體8字節(jié)對齊,那么被嵌套的結構要是8字節(jié)對齊,并且放在結構體中的第一個

如果保證呢:

變量或開辟的結構體、數(shù)組和切片值中的第一個64位字可以被認為是8字節(jié)對齊的。

開辟的意思就是好通過聲明,make,new方式創(chuàng)建的。就是說這樣創(chuàng)建的64為字可以保證是64為對齊的

Go語言中恰到好處的內(nèi)存對齊

在開始之前,希望你計算一下 Part1 共占用的大小是多少呢?

輸出結果:

這么一算, Part1 這一個結構體的占用內(nèi)存大小為 1+4+1+8+1 = 15 個字節(jié)。相信有的小伙伴是這么算的,看上去也沒什么毛病

真實情況是怎么樣的呢?我們實際調(diào)用看看,如下:

輸出結果:

最終輸出為占用 32 個字節(jié)。這與前面所預期的結果完全不一樣。這充分地說明了先前的計算方式是錯誤的。為什么呢?

在這里要提到 “內(nèi)存對齊” 這一概念,才能夠用正確的姿勢去計算,接下來我們詳細的講講它是什么

有的小伙伴可能會認為內(nèi)存讀取,就是一個簡單的字節(jié)數(shù)組擺放

上圖表示一個坑一個蘿卜的內(nèi)存讀取方式。但實際上 CPU 并不會以一個一個字節(jié)去讀取和寫入內(nèi)存。相反 CPU 讀取內(nèi)存是 一塊一塊讀取 的,塊的大小可以為 2、4、6、8、16 字節(jié)等大小。塊大小我們稱其為 內(nèi)存訪問粒度 。如下圖:

在樣例中,假設訪問粒度為 4。 CPU 是以每 4 個字節(jié)大小的訪問粒度去讀取和寫入內(nèi)存的。這才是正確的姿勢

另外作為一個工程師,你也很有必要學習這塊知識點哦 :)

在上圖中,假設從 Index 1 開始讀取,將會出現(xiàn)很崩潰的問題。因為它的內(nèi)存訪問邊界是不對齊的。因此 CPU 會做一些額外的處理工作。如下:

從上述流程可得出,不做 “內(nèi)存對齊” 是一件有點 "麻煩" 的事。因為它會增加許多耗費時間的動作

而假設做了內(nèi)存對齊,從 Index 0 開始讀取 4 個字節(jié),只需要讀取一次,也不需要額外的運算。這顯然高效很多,是標準的 空間換時間 做法

在不同平臺上的編譯器都有自己默認的 “對齊系數(shù)”,可通過預編譯命令 #pragma pack(n) 進行變更,n 就是代指 “對齊系數(shù)”。一般來講,我們常用的平臺的系數(shù)如下:

另外要注意,不同硬件平臺占用的大小和對齊值都可能是不一樣的。因此本文的值不是唯一的,調(diào)試的時候需按本機的實際情況考慮

輸出結果:

在 Go 中可以調(diào)用 unsafe.Alignof 來返回相應類型的對齊系數(shù)。通過觀察輸出結果,可得知基本都是 2^n ,最大也不會超過 8。這是因為我手提(64 位)編譯器默認對齊系數(shù)是 8,因此最大值不會超過這個數(shù)

在上小節(jié)中,提到了結構體中的成員變量要做字節(jié)對齊。那么想當然身為最終結果的結構體,也是需要做字節(jié)對齊的

接下來我們一起分析一下,“它” 到底經(jīng)歷了些什么,影響了 “預期” 結果

在每個成員變量進行對齊后,根據(jù)規(guī)則 2,整個結構體本身也要進行字節(jié)對齊,因為可發(fā)現(xiàn)它可能并不是 2^n ,不是偶數(shù)倍。顯然不符合對齊的規(guī)則

根據(jù)規(guī)則 2,可得出對齊值為 8?,F(xiàn)在的偏移量為 25,不是 8 的整倍數(shù)。因此確定偏移量為 32。對結構體進行對齊

Part1 內(nèi)存布局:axxx|bbbb|cxxx|xxxx|dddd|dddd|exxx|xxxx

通過本節(jié)的分析,可得知先前的 “推算” 為什么錯誤?

是因為實際內(nèi)存管理并非 “一個蘿卜一個坑” 的思想。而是一塊一塊。通過空間換時間(效率)的思想來完成這塊讀取、寫入。另外也需要兼顧不同平臺的內(nèi)存操作情況

在上一小節(jié),可得知根據(jù)成員變量的類型不同,其結構體的內(nèi)存會產(chǎn)生對齊等動作。那假設字段順序不同,會不會有什么變化呢?我們一起來試試吧 :-)

輸出結果:

通過結果可以驚喜的發(fā)現(xiàn),只是 “簡單” 對成員變量的字段順序進行改變,就改變了結構體占用大小

接下來我們一起剖析一下 Part2 ,看看它的內(nèi)部到底和上一位之間有什么區(qū)別,才導致了這樣的結果?

符合規(guī)則 2,不需要額外對齊

Part2 內(nèi)存布局:ecax|bbbb|dddd|dddd

通過對比 Part1 和 Part2 的內(nèi)存布局,你會發(fā)現(xiàn)兩者有很大的不同。如下:

仔細一看, Part1 存在許多 Padding。顯然它占據(jù)了不少空間,那么 Padding 是怎么出現(xiàn)的呢?

通過本文的介紹,可得知是由于不同類型導致需要進行字節(jié)對齊,以此保證內(nèi)存的訪問邊界

那么也不難理解,為什么 調(diào)整結構體內(nèi)成員變量的字段順序 就能達到縮小結構體占用大小的疑問了,是因為巧妙地減少了 Padding 的存在。讓它們更 “緊湊” 了。這一點對于加深 Go 的內(nèi)存布局印象和大對象的優(yōu)化非常有幫

網(wǎng)頁標題:go語言對齊技巧 對稱go怎么玩
網(wǎng)頁網(wǎng)址:http://muchs.cn/article44/dodhhhe.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供標簽優(yōu)化商城網(wǎng)站、網(wǎng)站排名企業(yè)網(wǎng)站制作、品牌網(wǎng)站建設、建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設