日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Go 内存对齐的那些事儿

發布時間:2024/4/11 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go 内存对齐的那些事儿 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在討論內存對齊前我們先看一個思考題,我們都知道Go的結構體在內存中是由一塊連續的內存表示的,那么下面的結構體占用的內存大小是多少呢?

type?ST1?struct?{A?byteB?int64C?byte }

在64位系統下 byte 類型就只占1字節,int64 占用的是8個字節,按照數據類型占的字節數推理,很快就能得出結論:這個結構體的內存大小是10個字節 (1 + 8 +1 )。這個推論到底對不對呢?我們讓 Golang 自己揭曉一下答案。

package?mainimport?("fmt""unsafe" )type?ST1?struct?{A?byteB?int64C?byte }func?main()?{fmt.Println("ST1.A 占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST1{}.A)))fmt.Println("ST1.A 對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST1{}.A)))fmt.Println("ST1.B 占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST1{}.B)))fmt.Println("ST1.B 對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST1{}.B)))fmt.Println("ST1.C 占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST1{}.C)))fmt.Println("ST1.C 對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST1{}.C)))fmt.Println("ST1結構體?占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST1{})))fmt.Println("ST1結構體?對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST1{}))) }##?輸出 ST1.A 占用的字節數是:1 ST1.A 對齊的字節數是:1 ST1.B 占用的字節數是:8 ST1.B 對齊的字節數是:8 ST1.C 占用的字節數是:1 ST1.C 對齊的字節數是:1 ST1結構體?占用的字節數是:24 ST1結構體?對齊的字節數是:8

Golang 告訴我們 ST1 結構體占用的字節數是24。但是每個字段占用的字節數總共加起來確實是只有10個字節,這是怎么回事呢?

因為字段B占用的字節數是8,內存對齊的字節數也是8,A字段所在的8個字節里不足以存放字段B,所以只好留下7個字節的空洞,在下一個 8 字節存放字段B。又因為結構體ST1是8字節對齊的(可以理解為占的內存空間必須是8字節的倍數,且起始地址能夠整除8),所以 C 字段占據了下一個8字節,但是又留下了7個字節的空洞。

這樣ST1結構體總共占用的字節數正好是 24 字節。

既然知道了 Go 編譯器在對結構體進行內存對齊的時候會在字段之間留下內存空洞,那么我們把只需要 1 個字節對齊的字段 C 放在需要 8 個字節內存對齊的字段 B 前面就能讓結構體 ST1 少占 8 個字節。下面我們把 ST1 的 C 字段放在 B 的前面再觀察一下 ST1 結構體的大小。

package?mainimport?("fmt""unsafe" )type?ST1?struct?{A?byteC?byteB?int64 }func?main()?{fmt.Println("ST1.A 占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST1{}.A)))fmt.Println("ST1.A 對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST1{}.A)))fmt.Println("ST1.B 占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST1{}.B)))fmt.Println("ST1.B 對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST1{}.B)))fmt.Println("ST1.C 占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST1{}.C)))fmt.Println("ST1.C 對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST1{}.C)))fmt.Println("ST1結構體?占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST1{})))fmt.Println("ST1結構體?對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST1{}))) }##?輸出ST1.A 占用的字節數是:1 ST1.A 對齊的字節數是:1 ST1.B 占用的字節數是:8 ST1.B 對齊的字節數是:8 ST1.C 占用的字節數是:1 ST1.C 對齊的字節數是:1 ST1結構體?占用的字節數是:16 ST1結構體?對齊的字節數是:8

重排字段后,ST1 結構體的內存布局變成了下圖這樣

僅僅只是調換了一下順序,結構體 ST1 就減少了三分之一的內存占用空間。在實際編程應用時大部分時候我們不用太過于注意內存對齊對數據結構空間的影響,不過作為工程師了解內存對齊這個知識還是很重要的,它實際上是一種典型的以空間換時間的策略。

內存對齊

操作系統在讀取數據的時候并非按照我們想象的那樣一個字節一個字節的去讀取,而是一個字一個字的去讀取。

字是用于表示其自然的數據單位,也叫machine word。字是系統用來一次性處理事務的一個固定長度。

字長 / 步長 就是一個字可容納的字節數,一般 N 位系統的字長是 (N / 8) 個字節。

因此,當 CPU 從存儲器讀數據到寄存器,或者從寄存器寫數據到存儲器,每次 IO 的數據長度是字長。如 32 位系統訪問粒度是 4 字節(bytes),64 位系統的就是 8 字節。當被訪問的數據長度為 n 字節且該數據的內存地址為 n 字節對齊,那么操作系統就可以高效地一次定位到數據,無需多次讀取、處理對齊運算等額外操作。

內存對齊的原則是:將數據盡量的存儲在一個字長內,避免跨字長的存儲

Go 官方文檔中對數據類型的內存對齊也有如下保證:

  • 對于任何類型的變量 x,unsafe.Alignof(x) 的結果最小為1 (類型最小是一字節對齊的)

  • 對于一個結構體類型的變量 x,unsafe.Alignof(x) 的結果為 x 的所有字段的對齊字節數中的最大值

  • 對于一個數組類型的變量 x , unsafe.Alignof(x) 的結果和此數組的元素類型的一個變量的對齊字節數相等,也就是 unsafe.Alignof(x) == unsafe.Alignof(x[i])

  • 下面這個表格列出了每種數據類型對齊的字節數

    數據類型對齊字節數
    bool, byte, unit8 int81
    uint16, int162
    uint32, int32, float32, complex644
    uint64, int64, float64, complex648
    array由其元素類型決定
    struct由其字段類型決定, 最小為1
    其他類型8

    零字節類型的對齊

    我們都知道 struct{} 類型占用的字節數是 0,但其實它的內存對齊數是 1,這么設定的原因為了保證當它作為結構體的末尾字段時,不會訪問到其他數據結構的地址。比如像下面這個結構體 ST2

    type?ST2?struct?{A?uint32B?uint64C?struct{} }

    雖然字段 C 占用的字節數為0,但是編譯器會為它補 8 個字節,這樣就能保證訪問字段 C 的時候不會訪問到其他數據結構的內存地址。

    type?ST2?struct?{A?uint32B?uint64C?struct{} }func?main()?{fmt.Println("ST2.C 占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST2{}.C)))fmt.Println("ST2.C 對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST2{}.C)))fmt.Println("ST2 結構體占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST2{}))) }##?輸出ST2.C 占用的字節數是:0 ST2.C 對齊的字節數是:1 ST2 結構體占用的字節數是:24

    當然因為 C 前一個字段 B 占據了整個字長,如果把 A 和 B 的順序調換一下,因為 A 只占 4 個字節,C 的對齊字節數是 1, 足夠排在這個字剩余的字節里。這樣一來 ST2 結構體的占用空間就能減少到 16 個字節。

    type?ST2?struct?{B?uint64A?uint32C?struct{} }func?main()?{fmt.Println("ST2.C 占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST2{}.C)))fmt.Println("ST2.C 對齊的字節數是:"?+?fmt.Sprint(unsafe.Alignof(ST2{}.C)))fmt.Println("ST2 結構體占用的字節數是:"?+?fmt.Sprint(unsafe.Sizeof(ST2{}))) }##?輸出 ST2.C 占用的字節數是:0 ST2.C 對齊的字節數是:1 ST2 結構體占用的字節數是:16

    總結

    內存對齊在我理解就是為了計算機訪問數據的效率,對于像結構體、數組等這樣的占用連續內存空間的復合數據結構來說:

    • 數據結構占用的字節數是對齊字節數的整數倍。

    • 數據結構的邊界地址能夠整除整個數據結構的對齊字節數。

    這樣 CPU 既減少了對內存的讀取次數,也不需要再對讀取到的數據進行篩選和拼接,是一種典型的以空間換時間的方法。

    希望通過這篇文章能讓你更了解 Go 語言也更了解內存對齊這個計算機操作系統減少內存訪問頻率的機制。

    總結

    以上是生活随笔為你收集整理的Go 内存对齐的那些事儿的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美成人午夜视频 | 久久精品香蕉 | 美国黄色一级视频 | 婷婷视频一区二区三区 | 黄瓜视频在线观看污 | 亚洲伊人av | 一级片视频网站 | 五月天综合激情 | 黄色av电影在线 | 亚洲男人的天堂在线观看 | 桃谷绘里香在线观看 | 香蕉人妻av久久久久天天 | 一区二区三区视频免费 | 国产日韩高清在线 | 经典杯子蛋糕日剧在线观看免费 | 日韩超碰在线 | 99热官网| 最好看的中文字幕 | 国产极品一区二区 | 成人动漫一区二区 | 欧美色图19p| 五月婷中文字幕 | 日韩丰满少妇无码内射 | 日韩欧美高清 | 日本少妇高潮喷水xxxxxxx | 污视频网站在线 | 日韩av在线导航 | 亚洲成人av综合 | 国产黄色免费视频 | 国产偷怕 | 国产综合在线播放 | 日韩一区在线视频 | 成人尤物| free性护士vidos猛交 | 亚洲黄色a | 久久依人 | 黄色a区| 婷婷亚洲视频 | 亚洲制服av| 免费观看a级片 | 一区免费 | 成人一级片视频 | 美丽的姑娘在线观看免费 | 日韩淫片| 亚洲欧洲成人在线 | 色臀| 国产欧美一区二区三区在线看蜜臀 | 日本欧美在线 | 免费看黄色的视频 | 成人欧美一区二区三区黑人一 | 国产九色 | 成人免费视频国产在线观看 | 老司机成人免费视频 | 亚洲永久在线观看 | 精品久久人人妻人人做人人 | 亚洲精品xxxxx | 人妻互换一区二区三区四区五区 | 9色视频| 噜噜吧噜噜色 | 国产男女猛烈无遮挡免费视频 | 九九黄色大片 | 99免费在线观看视频 | 天天操天天干天天干 | 米奇7777狠狠狠狠视频 | 二区三区 | 欧美精品欧美精品系列 | 综合天天 | 免费性网站 | 999精品在线视频 | 欧美干| 国产精品播放 | 亚洲精品高清无码视频 | 亚洲一区在线视频 | 免费在线观看亚洲 | 丁香花国语版普通话 | 免费看黄色片视频 | 激情综合丁香五月 | 成人免费视频免费观看 | 在线v | 亚洲黄色中文字幕 | 亚洲经典一区二区三区四区 | 美女福利网站 | 国产在线视频一区二区 | 亚洲欧美另类日韩 | 久久人人视频 | 99久久久久久 | 超碰网站在线 | 5a毛片 | 日本视频中文字幕 | 黄黄的视频在线观看 | 国产福利在线播放 | 岳奶大又白下面又肥又黑水多 | 亚洲三级图片 | 国产深喉视频一区二区 | 日韩中文字幕有码 | 少妇av一区二区三区无码 | 欧美一区二区三区婷婷月色 | 91av麻豆| 国产又粗又猛又爽又黄的视频小说 |