欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang內(nèi)存對(duì)齊的規(guī)則及實(shí)現(xiàn)

 更新時(shí)間:2023年08月08日 15:16:36   作者:~kiss~  
本文介紹了Golang內(nèi)存對(duì)齊的規(guī)則及實(shí)現(xiàn),通過合理的內(nèi)存對(duì)齊,可以提高程序的執(zhí)行效率和性能,通過對(duì)本文的閱讀,讀者可以更好地理解Golang內(nèi)存對(duì)齊的原理和技巧,并應(yīng)用于實(shí)際編程中

什么是內(nèi)存對(duì)齊?

編譯器會(huì)將數(shù)據(jù)按照特定的規(guī)則,把數(shù)據(jù)安排到合適的存儲(chǔ)地址上,并占用合適的地址長度

為什么要內(nèi)存對(duì)齊

保證程序順利高效的運(yùn)行,可以讓CPU快速從內(nèi)存中存取到字段,避免資源浪費(fèi)

內(nèi)存對(duì)齊規(guī)則

1、起始的存儲(chǔ)地址 必須是 內(nèi)存對(duì)齊邊界 的倍數(shù)。

2、整體占用字節(jié)數(shù) 必須是 內(nèi)存對(duì)齊邊界 的倍數(shù)。

Tip:先聲明兩個(gè)概念 ↓ ↓ 

  • 內(nèi)存對(duì)齊邊界:結(jié)構(gòu)體所有元素中,哪個(gè)元素占用的字節(jié)數(shù)大,那么這個(gè)元素占用的字節(jié)數(shù)就是內(nèi)存對(duì)齊邊界 
  • 對(duì)齊邊界:結(jié)構(gòu)體中每個(gè)元素自己占用的字節(jié)數(shù)

通過下邊的示例來理解內(nèi)存對(duì)齊的規(guī)則

首先我們定義一個(gè)結(jié)構(gòu)體:

type S struct {
   A uint8     // byte:1
   B int32     // byte:4
   C int16     // byte:2
   D int64     // byte:8
   E [2]string // byte總和:32 -->string類型數(shù)組,總共2個(gè)元素,每個(gè)元素包含2部分內(nèi)容:
   			   // 內(nèi)容1:ptr,指向存放數(shù)據(jù)的地址,byte:8:  內(nèi)容2:len,標(biāo)識(shí)字符串長度的整數(shù)值,byte:8
   F struct{}  // zero size field
}

步驟一:確定內(nèi)存對(duì)齊邊界

統(tǒng)計(jì)出結(jié)構(gòu)體中所有的元素分別占用的字節(jié)數(shù),占用最大的字節(jié)數(shù)就是內(nèi)存對(duì)齊邊界,在這個(gè)示例中的內(nèi)存對(duì)齊邊界就是 8    Tip:如果不知道怎樣確定內(nèi)存對(duì)齊邊界,可以使用unsafe.Alignof()函數(shù)打印每個(gè)元素的對(duì)齊系數(shù),打印中的最大值就是內(nèi)存對(duì)齊邊界:

func main() {
	fmt.Println(unsafe.Alignof(S{}.A))   // output: 1
	fmt.Println(unsafe.Alignof(S{}.B))  // output: 4
	fmt.Println(unsafe.Alignof(S{}.C))  // output: 2
	fmt.Println(unsafe.Alignof(S{}.D))  // output: 8
	fmt.Println(unsafe.Alignof(S{}.E))  // output: 8
	fmt.Println(unsafe.Alignof(S{}.F))  // output: 1
	fmt.Println(unsafe.Sizeof(S{}))		//可以直接打印出結(jié)構(gòu)體所占用的字節(jié)數(shù)
}

步驟二:確定起始存儲(chǔ)地址

內(nèi)存對(duì)齊規(guī)則第一條:起始的存儲(chǔ)地址 必須是 內(nèi)存對(duì)齊邊界 的倍數(shù)。也就是(起始地址addr)%(內(nèi)存對(duì)齊邊界)=0,在我們示例中起始地址就是addr%8=0,我們從0地址開始,為了方便看,我們先用圖來展示地址存儲(chǔ)分布圖

起始地址為0,0%8=0,符合條件,那我們就從0開始存儲(chǔ)數(shù)據(jù)

其中元素A占用1個(gè)字節(jié),并且0%1=0,符合條件,第0個(gè)地址分配給A;

元素B占用4個(gè)字節(jié),從1個(gè)地址分配的話,1%4≠0,只有4%4=0,所以把第4-7個(gè)地址分配給B;

以此類推······ 具體分配如下

元素A:1個(gè)字節(jié),占用第0個(gè)相對(duì)地址空間,      0%1 =0(起始地址為0,內(nèi)存邊界為1)
元素B:4個(gè)字節(jié),占用第4-7個(gè)相對(duì)地址空間,    4%4 =0(起始地址為4,內(nèi)存邊界為4)
元素C:2個(gè)字節(jié),占用第8-9個(gè)相對(duì)地址空間,    8%2 =0(起始地址為8,內(nèi)存邊界為2)
元素D:8個(gè)字節(jié),占用第16-23個(gè)相對(duì)地址空間,  16%8=0(起始地址為16,內(nèi)存邊界為8)
元素E:8*2*2個(gè)字節(jié),占用第24-31和32-39和40-47和48-55個(gè)相對(duì)地址空間,24%8=0...(起始地址為24,內(nèi)存邊界為8...)
元素F:zero size field,占用第56個(gè)相對(duì)地址空間,     56%1=0 (起始地址為56,內(nèi)存邊界為1)

最終內(nèi)存在第56個(gè)相對(duì)地址空間分配完畢,但是我們的地址空間是從0開始計(jì)算的,所以目前來看結(jié)構(gòu)體總共占用57個(gè)字節(jié)!

步驟三:確定結(jié)構(gòu)體占用字節(jié)數(shù)

我們?cè)诓襟E二中排列出了結(jié)構(gòu)體中元素的存放地址,整體元素占用57個(gè)字節(jié),但是到這里還不算完事兒,因?yàn)槲覀冞€沒有執(zhí)行第二條的內(nèi)存對(duì)齊規(guī)則–>整體占用字節(jié)數(shù) 必須是 內(nèi)存對(duì)齊邊界 的倍數(shù)。我們的內(nèi)存對(duì)齊邊界為8,而57不是8的倍數(shù),所以我們需要擴(kuò)張字節(jié)空間到8的倍數(shù),延伸到64,也就是擴(kuò)張到到圖中的第63個(gè)相對(duì)地址空間。這個(gè)結(jié)構(gòu)體占用的字節(jié)數(shù)為64字節(jié)!

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

通過上邊的示例與圖表我們不難看出,其中還有好多個(gè)地址空間被浪費(fèi)掉了,這些沒被利用的地址空間,go語言會(huì)進(jìn)行padding操作來對(duì)這些空間進(jìn)行填充,使這些空間變成合法的內(nèi)存空間。

我們?cè)偎伎家幌?,如何才能減少地址空間的浪費(fèi)呢?能不能通過重新排列元素的位置來合理的分配地址空間呢?答案當(dāng)然是肯定的,我們可以通過合理排列元素的定義順序來減少地址空間的浪費(fèi)。

我們先看結(jié)論,下邊是重新排列后的結(jié)構(gòu)體:

type S1 struct {
	A uint8
	F struct{}
	C int16
	B int32
	D int64
	E [2]string
}

再看一下重新分配地址空間的圖標(biāo):

起始地址為0,0%8=0,符合條件,我們就從0開始存儲(chǔ)數(shù)據(jù)

其中元素A占用1個(gè)字節(jié),并且0%1=0,符合條件,第0個(gè)地址分配給A;       元素F占用1個(gè)字節(jié),1%1=0,符合條件,將第1個(gè)地址分配給B;       以此類推······ 具體分配如下

元素A:1個(gè)字節(jié),占用第0個(gè)相對(duì)地址空間,          0%1 =0(起始地址為0,內(nèi)存邊界為1)
元素F:zero size field,占用第1個(gè)相對(duì)地址空間,1%1 =0(起始地址為1,內(nèi)存邊界為1)
元素C:2個(gè)字節(jié),占用第2-3個(gè)相對(duì)地址空間,        2%2 =0(起始地址為2,內(nèi)存邊界為2)
元素B:4個(gè)字節(jié),占用第4-7個(gè)相對(duì)地址空間,        4%4=0(起始地址為4,內(nèi)存邊界為4)
元素D:8個(gè)字節(jié),占用第8-15個(gè)相對(duì)地址空間,        8%8=0(起始地址為8,內(nèi)存邊界為8)
元素E:8*2*2個(gè)字節(jié),占用第16-23和24-31和32-39和40-47個(gè)相對(duì)地址空間,16%8=0... (起始地址為16,內(nèi)存邊界為8...)

最終內(nèi)存在第47個(gè)相對(duì)地址空間分配完畢,但是我們的地址空間是從0開始計(jì)算的,所以目前來看結(jié)構(gòu)體總共占用48個(gè)字節(jié)!并且48還是內(nèi)存對(duì)齊邊界值8的整數(shù)倍,所以結(jié)構(gòu)體最終占用48個(gè)字節(jié)!

我們可以很明顯的看出來,在我們改變?cè)氐亩x順序后,占用的字節(jié)空間從64字節(jié)減少到了48字節(jié),內(nèi)存空間得到了充分的優(yōu)化?。?!這也是一個(gè)結(jié)論所在,我們?cè)诮Y(jié)構(gòu)體定義變量的時(shí)候,盡量將相同類型的變量定義在一起,將占用字節(jié)較少的變量類型放在一塊。

到此這篇關(guān)于Golang內(nèi)存對(duì)齊的規(guī)則及實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang內(nèi)存對(duì)齊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言異常處理(Panic和recovering)用法詳解

    Go語言異常處理(Panic和recovering)用法詳解

    異常處理是程序健壯性的關(guān)鍵,往往開發(fā)人員的開發(fā)經(jīng)驗(yàn)的多少從異常部分處理上就能得到體現(xiàn)。Go語言中沒有Try?Catch?Exception機(jī)制,但是提供了panic-and-recover機(jī)制,本文就來詳細(xì)講講他們的用法
    2022-07-07
  • Go語言封裝MinIO相關(guān)操作詳解

    Go語言封裝MinIO相關(guān)操作詳解

    MinIO?是一個(gè)高性能的對(duì)象存儲(chǔ)服務(wù),兼容?Amazon?S3?API,廣泛用于存儲(chǔ)和管理海量數(shù)據(jù),本文將介紹如何用?Go?語言封裝一個(gè)簡單的?MinIO?操作包,需要的可以參考下
    2024-11-11
  • Golang中多個(gè)if代碼優(yōu)化小技巧

    Golang中多個(gè)if代碼優(yōu)化小技巧

    這篇文章主要為大家詳細(xì)介紹了Golang中一些常用的if代碼優(yōu)化小技巧,w文中的示例代碼簡潔易懂,具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • Goland使用Go Modules創(chuàng)建/管理項(xiàng)目的操作

    Goland使用Go Modules創(chuàng)建/管理項(xiàng)目的操作

    這篇文章主要介紹了Goland使用Go Modules創(chuàng)建/管理項(xiàng)目的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Golang并發(fā)發(fā)送HTTP請(qǐng)求的各種方法

    Golang并發(fā)發(fā)送HTTP請(qǐng)求的各種方法

    在 Golang 領(lǐng)域,并發(fā)發(fā)送 HTTP 請(qǐng)求是優(yōu)化 Web 應(yīng)用程序的一項(xiàng)重要技能,本文探討了實(shí)現(xiàn)此目的的各種方法,從基本的 goroutine 到涉及通道和sync.WaitGroup 的高級(jí)技術(shù),需要的朋友可以參考下
    2024-02-02
  • golang中import cycle not allowed解決的一種思路

    golang中import cycle not allowed解決的一種思路

    這篇文章主要給大家介紹了關(guān)于golang中import cycle not allowed解決的一種思路,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • go語言實(shí)現(xiàn)將重要數(shù)據(jù)寫入圖片中

    go語言實(shí)現(xiàn)將重要數(shù)據(jù)寫入圖片中

    本文給大家分享的是go語言實(shí)現(xiàn)將數(shù)據(jù)的二進(jìn)制形式寫入圖像紅色通道數(shù)據(jù)二進(jìn)制的低位,從而實(shí)現(xiàn)將重要數(shù)據(jù)隱藏,有需要的小伙伴參考下吧。
    2015-03-03
  • golang 兩個(gè)go程輪流打印一個(gè)切片的實(shí)現(xiàn)

    golang 兩個(gè)go程輪流打印一個(gè)切片的實(shí)現(xiàn)

    這篇文章主要介紹了golang 兩個(gè)go程輪流打印一個(gè)切片的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Go語言中 Channel 詳解

    Go語言中 Channel 詳解

    Go 語言中的 channel 是實(shí)現(xiàn) goroutine 間無鎖通信的關(guān)鍵機(jī)制,他使得寫多線程并發(fā)程序變得簡單、靈活、觸手可得。下面就個(gè)人理解對(duì) channel 使用過程中應(yīng)該注意的地方進(jìn)行一個(gè)簡要的總結(jié)。
    2018-10-10
  • Windows上安裝Go并配置環(huán)境變量(圖文步驟)

    Windows上安裝Go并配置環(huán)境變量(圖文步驟)

    開始使用Go創(chuàng)建應(yīng)用程序之前,需要設(shè)置開發(fā)環(huán)境,本文主要介紹了Windows上安裝Go并配置環(huán)境變量,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08

最新評(píng)論