自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go 內(nèi)存分配:結(jié)構(gòu)體中的優(yōu)化技巧

開(kāi)發(fā) 前端
為什么字段c的偏移量是24?字段b中的字符串看起來(lái)比16個(gè)字節(jié)要長(zhǎng)得多,如果字符串的偏移量是8,那么字段c的偏移量應(yīng)該更大一些。

在使用Golang進(jìn)行內(nèi)存分配時(shí),我們需要遵循一系列規(guī)則。在深入了解這些規(guī)則之前,我們需要先了解變量的對(duì)齊方式。

Golang的unsafe包中有一個(gè)函數(shù)Alignof,簽名如下:

func Alignof(x ArbitraryType) uintptr

對(duì)于任何類(lèi)型為v的變量x,AlignOf函數(shù)會(huì)返回該變量的對(duì)齊方式。我們將對(duì)齊方式記為m?,F(xiàn)在,Golang確保m是滿足變量x的內(nèi)存地址 % m == 0的最大可能數(shù),也就是說(shuō),變量x的內(nèi)存地址是m的倍數(shù)。

讓我們來(lái)看看一些數(shù)據(jù)類(lèi)型的對(duì)齊方式:

  • byte, int8, uint8 -> 1
  • int16, uint16 -> 2
  • int32, uint32, float32, complex64 -> 4
  • int, int64, uint64, float64, complex128 -> 8
  • string, slice -> 8

對(duì)于結(jié)構(gòu)體中的字段,行為可能會(huì)有所不同,詳細(xì)信息請(qǐng)參考包的文檔。

為了更好地理解結(jié)構(gòu)體內(nèi)存分配的情況,我們將使用unsafe包中的另一個(gè)函數(shù)Offsetof。該函數(shù)返回字段相對(duì)于結(jié)構(gòu)體起始位置的位置,換句話說(shuō),它返回字段起始位置與結(jié)構(gòu)體起始位置之間的字節(jié)數(shù)。

func Offsetof(x ArbitraryType) uintptr

為了更好地理解結(jié)構(gòu)體內(nèi)存分配,讓我們以一個(gè)示例結(jié)構(gòu)體為例:

type Example struct {
    a int8
    b string
    c int8
    d int32
}

現(xiàn)在,我們將找出類(lèi)型為Example的變量所占用的總內(nèi)存,并嘗試優(yōu)化分配。

var v = Example{
    a: 10,
    b: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus rhoncus.",
    c: 20,
    d: 100,
}
fmt.Println("字段a的偏移量:", unsafe.Offsetof(v.a)) // 輸出:0
fmt.Println("字段b的偏移量:", unsafe.Offsetof(v.b)) // 輸出:8
fmt.Println("字段c的偏移量:", unsafe.Offsetof(v.c)) // 輸出:24
fmt.Println("字段d的偏移量:", unsafe.Offsetof(v.d)) // 輸出:28

現(xiàn)在,問(wèn)題出現(xiàn)了:“為什么結(jié)構(gòu)體中字段b的偏移量是8?它應(yīng)該是1,因?yàn)樽侄蝍的類(lèi)型是int8,只占用1個(gè)字節(jié)?!被氐阶址?dāng)?shù)據(jù)類(lèi)型的對(duì)齊方式,它的值為8,這意味著地址需要被8整除,因此在其中插入了7個(gè)字節(jié)的“填充”,以確保這種行為。

為什么字段c的偏移量是24?字段b中的字符串看起來(lái)比16個(gè)字節(jié)要長(zhǎng)得多,如果字符串的偏移量是8,那么字段c的偏移量應(yīng)該更大一些。

上述問(wèn)題的答案是,在Go中,字符串并不是在結(jié)構(gòu)體內(nèi)的同一位置分配內(nèi)存的。有一個(gè)單獨(dú)的數(shù)據(jù)結(jié)構(gòu)來(lái)保存字符串描述符,并且該字符串描述符以原地方式存儲(chǔ)在結(jié)構(gòu)體中,用于類(lèi)型為string的字段,該描述符的大小為16個(gè)字節(jié)。

現(xiàn)在,讓我們來(lái)看看unsafe包中的另一個(gè)函數(shù)Sizeof。正如其名稱所示,該函數(shù)估計(jì)并返回類(lèi)型為x的變量所占用的字節(jié)數(shù)。

注意:它是根據(jù)結(jié)構(gòu)體中可能存在的不同大小的字段來(lái)估計(jì)大小的。

func Sizeof(x ArbitraryType) uintptr

現(xiàn)在,讓我們來(lái)看看我們的結(jié)構(gòu)體Example的大小。

fmt.Println("Example的大?。?, unsafe.Sizeof(v)) // 輸出:32

我們?nèi)绾蝺?yōu)化這個(gè)結(jié)構(gòu)體以最小化填充呢?

為了優(yōu)化這個(gè)結(jié)構(gòu)體的內(nèi)存,我們將查看不同數(shù)據(jù)類(lèi)型的對(duì)齊方式,并嘗試減少填充。讓我們嘗試將兩個(gè)int8類(lèi)型的字段放在一起。

type y struct {
    a int8
    c int8
    b string
    d int32
}

var v = y{}
fmt.Println("字段a的偏移量:", unsafe.Offsetof(v.a)) // 輸出:0
fmt.Println("字段b的偏移量:", unsafe.Offsetof(v.b)) // 輸出:8
fmt.Println("字段c的偏移量:", unsafe.Offsetof(v.c)) // 輸出:1
fmt.Println("字段d的偏移量:", unsafe.Offsetof(v.d)) // 輸出:24
fmt.Println("Example的大?。?, unsafe.Sizeof(v)) // 輸出:32

太棒了,我們?nèi)サ袅艘恍┨畛洌菫槭裁创笮∪匀皇?2?大小應(yīng)該是1(a)+ 1(c)+ 6(填充)+ 16(b)+ 4(d)= 28

現(xiàn)在,當(dāng)結(jié)構(gòu)體的最后一個(gè)字段與架構(gòu)的對(duì)齊要求不完全一致時(shí),會(huì)在最后一個(gè)字段之后添加填充,以確保結(jié)構(gòu)體的整體大小是其字段中最大對(duì)齊要求的倍數(shù)。因?yàn)樽址當(dāng)?shù)據(jù)類(lèi)型的最大對(duì)齊方式為8,所以額外添加了填充,使大小成為8的倍數(shù),即在末尾填充了4個(gè)字節(jié),使大小為32字節(jié)。

我們能否進(jìn)一步減少填充,使其更加優(yōu)化?

讓我們嘗試通過(guò)移動(dòng)字段位置來(lái)實(shí)現(xiàn)。

type y struct {
    b string
    d int32
    a int8
    c int8
}

var v = y{}
fmt.Println("字段a的偏移量:", unsafe.Offsetof(v.a)) // 輸出:20
fmt.Println("字段b的偏移量:", unsafe.Offsetof(v.b)) // 輸出:0
fmt.Println("字段c的偏移量:", unsafe.Offsetof(v.c)) // 輸出:21
fmt.Println("字段d的偏移量:", unsafe.Offsetof(v.d)) // 輸出:16
fmt.Println("Example的大小:", unsafe.Sizeof(v)) // 輸出:24

我們可以看到,通過(guò)重新排列字段的位置,使得對(duì)齊需要最小化填充,我們已經(jīng)將結(jié)構(gòu)體的大小從32減小到24,這是內(nèi)存優(yōu)化的巨大進(jìn)步,達(dá)到了25%。

當(dāng)前的內(nèi)存占用是16(b)+ 4(d)+ 1(a)+ 1(b)+ 2(填充)。

遺憾的是,由于語(yǔ)言和架構(gòu)的限制,我們無(wú)法進(jìn)一步去除填充。

責(zé)任編輯:武曉燕 來(lái)源: 愛(ài)發(fā)白日夢(mèng)的后端
相關(guān)推薦

2021-12-20 07:59:07

Go語(yǔ)言結(jié)構(gòu)體

2020-12-02 09:10:22

Go結(jié)構(gòu)數(shù)據(jù)類(lèi)型

2023-07-29 15:03:29

2021-04-20 09:00:48

Go 語(yǔ)言結(jié)構(gòu)體type

2021-02-28 13:22:54

Java內(nèi)存代碼

2021-01-06 09:47:51

內(nèi)存Go語(yǔ)言

2023-10-10 13:58:00

C語(yǔ)言代碼結(jié)構(gòu)體

2010-02-04 14:58:06

C++內(nèi)存分配

2021-12-21 08:51:13

Go數(shù)據(jù)Model

2011-08-10 09:06:44

內(nèi)存內(nèi)存優(yōu)化

2021-11-02 14:54:41

Go結(jié)構(gòu)體標(biāo)簽

2010-08-10 10:17:44

Flex內(nèi)存

2023-01-10 09:18:37

Go內(nèi)存分配逃逸

2021-11-02 12:19:18

Go函數(shù)結(jié)構(gòu)

2022-11-30 08:19:15

內(nèi)存分配Go逃逸分析

2020-05-06 18:53:23

Go編程語(yǔ)言

2024-01-15 11:12:28

Go內(nèi)存開(kāi)發(fā)

2020-11-30 06:17:03

Go語(yǔ)言

2020-11-26 06:40:24

Go語(yǔ)言基礎(chǔ)

2020-12-02 08:45:36

Go語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)