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

golang 內(nèi)存對齊的實現(xiàn)

 更新時間:2024年08月14日 11:00:04   作者:m舊褲子  
在代碼編譯階段,編譯器會對數(shù)據(jù)的存儲布局進行對齊優(yōu)化,本文主要介紹了golang 內(nèi)存對齊的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下

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

在訪問特定類型變量的時候通常在特定的內(nèi)存地址訪問,這就需要對這些數(shù)據(jù)在內(nèi)存中存放的位置有限制,各種類型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個接一個的排放,這就是對齊。

內(nèi)存對齊是編譯器的管轄范圍。表現(xiàn)為:編譯器為程序中的每個“數(shù)據(jù)單元”安排在適當?shù)奈恢蒙稀?/p>

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

  • 有些CPU可以訪問任意地址上的任意數(shù)據(jù),而有些CPU只能在特定地址訪問數(shù)據(jù),因此不同硬件平臺具有差異性,這樣的代碼就不具有移植性,如果在編譯時,將分配的內(nèi)存進行對齊,這就具有平臺可以移植性了。

  • CPU 訪問內(nèi)存時并不是逐個字節(jié)訪問,而是以字長(word size)為單位訪問,例如 32位的CPU 字長是4字節(jié),64位的是8字節(jié)。如果變量的地址沒有對齊,可能需要多次訪問才能完整讀取到變量內(nèi)容,而對齊后可能就只需要一次內(nèi)存訪問,因此內(nèi)存對齊可以減少CPU訪問內(nèi)存的次數(shù),加大CPU訪問內(nèi)存的吞吐量。

假設(shè)每次訪問的步長為4個字節(jié),如果未經(jīng)過內(nèi)存對齊,獲取b的數(shù)據(jù)需要進行兩次內(nèi)存訪問,最后再進行數(shù)據(jù)整理得到b的完整數(shù)據(jù):

在這里插入圖片描述

如果經(jīng)過內(nèi)存對齊,一次內(nèi)存訪問就能得到b的完整數(shù)據(jù),減少了一次內(nèi)存訪問:

在這里插入圖片描述

golang中unsafe.AlignOf()函數(shù)

unsafe.AlignOf(x) 方法的返回值是 m,當變量進行內(nèi)存對齊時,需要保證分配到 x 的內(nèi)存地址能夠整除 m。因此可以通過這個方法,確定變量x 在內(nèi)存對齊時的地址:

  • 對于任意類型的變量 x ,unsafe.Alignof(x) 至少為 1。
  • 對于 struct 結(jié)構(gòu)體類型的變量 x,計算 x 每一個字段 f 的 unsafe.Alignof(x.f),unsafe.Alignof(x) 等于其中的最大值。
  • 對于 array 數(shù)組類型的變量x,unsafe.Alignof(x) 等于構(gòu)成數(shù)組的元素類型的對齊倍數(shù)。

對于系統(tǒng)內(nèi)置基礎(chǔ)類型變量 x ,unsafe.Alignof(x) 的返回值就是 min(字長/8,unsafe.Sizeof(x)),即計算機字長與類型占用內(nèi)存的較小值:

func main() {
  fmt.Println(unsafe.Alignof(int(1))) // 1 -- min(8,1)
  fmt.Println(unsafe.Alignof(int32(1))) // 4 -- min (8,4)
  fmt.Println(unsafe.Alignof(int64(1))) // 8 -- min (8,8)
  fmt.Println(unsafe.Alignof(complex128(1))) // 8 -- min(8,16)
}  

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

  • 成員對齊規(guī)則

針對一個基礎(chǔ)類型變量,如果 unsafe.AlignOf() 返回的值是 m,那么該變量的地址需要 被m整除 (如果當前地址不能整除,填充空白字節(jié),直至可以整除)。

  • 整體對齊規(guī)則

針對一個結(jié)構(gòu)體,如果 unsafe.AlignOf() 返回值是 m,需要保證該結(jié)構(gòu)體整體內(nèi)存占用是 m的整數(shù)倍,如果當前不是整數(shù)倍,需要在后面填充空白字節(jié)。

通過內(nèi)存對齊后,就可以在保證在訪問一個變量地址時:

  • 如果該變量占用內(nèi)存小于字長:保證一次訪問就能得到數(shù)據(jù);
  • 如果該變量占用內(nèi)存大于字長:保證第一次內(nèi)存訪問的首地址,是該變量的首地址。

eg:

type A struct {
	a int32
	b int64
	c int32
}

func main() {
	fmt.Println(unsafe.Sizeof(A{1, 1, 1}))  // 24
}

第一個字段是 int32 類型,unsafe.Sizeof(int32(1))=4,內(nèi)存占用為4個字節(jié),同時unsafe.Alignof(int32(1)) = 4,內(nèi)存對齊需保證變量首地址可以被4整除,我們假設(shè)地址從0開始,0可以被4整除:

在這里插入圖片描述

2. 第二個字段是 int64 類型,unsafe.Sizeof(int64(1)) = 8,內(nèi)存占用為 8 個字節(jié),同unsafe.Alignof(int64(1)) = 8,需保證變量放置首地址可以被8整除,當前地址為4,距離4最近的且可以被8整除的地址為8,因此需要添加四個空白字節(jié),從8開始放置:

S

第三個字段是 int32 類型,unsafe.Sizeof(int32(1))=4,內(nèi)存占用為4個字節(jié),同時unsafe.Alignof(int32(1)) = 4,內(nèi)存對齊需保證變量首地址可以被4整除,當前地址為16,16可以被4整除:

在這里插入圖片描述

所有成員對齊都已經(jīng)完成,現(xiàn)在我們需要看一下整體對齊規(guī)則:unsafe.Alignof(A{}) = 8,即三個變量成員的最大值,內(nèi)存對齊需要保證該結(jié)構(gòu)體的內(nèi)存占用是 8 的整數(shù)倍,當前內(nèi)存占用是 20個字節(jié),因此需要再補充4個字節(jié):

在這里插入圖片描述

最終該結(jié)構(gòu)體的內(nèi)存占用為 24字節(jié)。

type B struct {
	a int32
	b int32
	c int64
}

func main() {
	fmt.Println(unsafe.Sizeof(B{1, 1, 1}))  // 16
}

第一個字段是 int32 類型,unsafe.Sizeof(int32(1))=4,內(nèi)存占用為4個字節(jié),同時unsafe.Alignof(int32(1)) = 4,內(nèi)存對齊需保證變量首地址可以被4整除,我們假設(shè)地址從0開始,0可以被4整除:

在這里插入圖片描述

第二個字段是 int32 類型,unsafe.Sizeof(int32(1))=4,內(nèi)存占用為4個字節(jié),同時unsafe.Alignof(int32(1)) = 4,內(nèi)存對齊需保證變量首地址可以被4整除,當前地址為4,4可以被4整除:

在這里插入圖片描述

第三個字段是 int64 類型,unsafe.Sizeof(int64(1))=8,內(nèi)存占用為8個字節(jié),同時unsafe.Alignof(int64(1)) = 8,內(nèi)存對齊需保證變量首地址可以被8整除,當前地址為8,8可以被8整除:

在這里插入圖片描述

所有成員對齊都已經(jīng)完成,現(xiàn)在我們需要看一下整體對齊規(guī)則:unsafe.Alignof(B{}) = 8,即三個變量成員的最大值,內(nèi)存對齊需要保證該結(jié)構(gòu)體的內(nèi)存占用是 8 的整數(shù)倍,當前內(nèi)存占用是 16個字節(jié),已經(jīng)符合規(guī)則,最終該結(jié)構(gòu)體的內(nèi)存占用為 16個字節(jié)。

空結(jié)構(gòu)體對齊規(guī)則

如果空結(jié)構(gòu)體作為結(jié)構(gòu)體的內(nèi)置字段:當變量位于結(jié)構(gòu)體的前面和中間時,不會占用內(nèi)存;當該變量位于結(jié)構(gòu)體的末尾位置時,需要進行內(nèi)存對齊,內(nèi)存占用大小和前一個變量的大小保持一致。

type C struct {
	a struct{}
	b int64
	c int64
}

type D struct {
	a int64
	b struct{}
	c int64
}

type E struct {
	a int64
	b int64
	c struct{}
}

type F struct {
	a int32
	b int32
	c struct{}
}

func main() {
	fmt.Println(unsafe.Sizeof(C{})) // 16
	fmt.Println(unsafe.Sizeof(D{})) // 16
	fmt.Println(unsafe.Sizeof(E{})) // 24
    fmt.Println(unsafe.Sizeof(F{})) // 12
}

參考:https://juejin.cn/post/7077833959047954463

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

相關(guān)文章

  • golang頻率限制 rate詳解

    golang頻率限制 rate詳解

    這篇文章主要介紹了golang頻率限制 rate詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go工具鏈之go tool cover使用方法和示例詳解

    Go工具鏈之go tool cover使用方法和示例詳解

    go tool cover是Go工具鏈中的一個命令,作用是分析測試用例的代碼覆蓋率,本文將對go tool cover 作用,使用方法和使用場景作一個簡單的介紹,感興趣的同學(xué)可以參考閱讀一下
    2023-07-07
  • go語言import報錯處理圖文詳解

    go語言import報錯處理圖文詳解

    今天本來想嘗試一下go語言中公有和私有的方法,結(jié)果import其他包的時候直接報錯了,下面這篇文章主要給大家介紹了關(guān)于go語言import報錯處理的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • 基于Go+WebSocket實現(xiàn)實時通信功能

    基于Go+WebSocket實現(xiàn)實時通信功能

    在互聯(lián)網(wǎng)應(yīng)用程序中,實時通信是一種非常重要的功能,WebSocket 是一種基于 TCP 的協(xié)議,它允許客戶端和服務(wù)器之間進行雙向通信,本文將介紹如何使用 Golang 創(chuàng)建單獨的 WebSocket 會話,以實現(xiàn)實時通信功能,需要的朋友可以參考下
    2023-10-10
  • Go語言學(xué)習(xí)之goroutine詳解

    Go語言學(xué)習(xí)之goroutine詳解

    Goroutine是建立在線程之上的輕量級的抽象。它允許我們以非常低的代價在同一個地址空間中并行地執(zhí)行多個函數(shù)或者方法,這篇文章主要介紹了Go語言學(xué)習(xí)之goroutine的相關(guān)知識,需要的朋友可以參考下
    2020-02-02
  • Go語言基礎(chǔ)類型及常量用法示例詳解

    Go語言基礎(chǔ)類型及常量用法示例詳解

    這篇文章主要為大家介紹了Go語言基礎(chǔ)類型及常量的用法及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • Golang解析yaml文件操作指南

    Golang解析yaml文件操作指南

    之前一直從事java開發(fā),習(xí)慣了使用yaml文件的格式,尤其是清晰的層次結(jié)構(gòu)、注釋,下面這篇文章主要給大家介紹了關(guān)于Golang解析yaml文件的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • Go語言加解密利器之go-crypto庫用法解析

    Go語言加解密利器之go-crypto庫用法解析

    在軟件開發(fā)中,數(shù)據(jù)安全和隱私保護越來越受到重視,go-crypto?庫應(yīng)運而生,它是一個專為?Golang?設(shè)計的加密解密工具庫,下面就跟隨小編一起來看看它的具體使用吧
    2024-11-11
  • 詳解在Go語言單元測試中如何解決文件依賴問題

    詳解在Go語言單元測試中如何解決文件依賴問題

    現(xiàn)如今的?Web?應(yīng)用程序往往采用?RESTful?API?接口形式對外提供服務(wù),后端接口直接向前端返回?HTML?文件的情況越來越少,所以在程序中操作文件的場景也變少了,在編寫單元測試時,文件就成了被測試代碼的外部依賴,本文就來講解下測試過程中如何解決文件外部依賴問題
    2023-08-08
  • Go結(jié)合反射將結(jié)構(gòu)體轉(zhuǎn)換成Excel的過程詳解

    Go結(jié)合反射將結(jié)構(gòu)體轉(zhuǎn)換成Excel的過程詳解

    這篇文章主要介紹了Go結(jié)合反射將結(jié)構(gòu)體轉(zhuǎn)換成Excel的過程詳解,大概思路是在Go的結(jié)構(gòu)體中每個屬性打上一個excel標簽,利用反射獲取標簽中的內(nèi)容,作為表格的Header,需要的朋友可以參考下
    2022-06-06

最新評論