網站首頁 編程語言 正文
前言
結構體在Go
語言中是一個很重要的部分,在項目中會經常用到,大家在寫Go
時有沒有注意過,一個struct
所占的空間不一定等于各個字段加起來的空間之和,甚至有時候把字段的順序調整一下,struct
的所占空間不一樣,接下來通過這篇文章來看一下結構體在內存中是怎么分布的?通過對內存布局的了解,可以幫助我們寫出更優質的代碼。感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
結構體內存布局
結構體大小
結構體實際上就是由各種類型的數據組合而成的一種符合數據類型,一個結構體變量的大小是由結構體中的字段決定。結構體和它所包含的數據在內存中是以連續塊的形式存在的。我們可以借助unsafe.Sizeof
方法,來獲取:
package main import ( "fmt" "unsafe" ) type Test struct { T1 int8 // 1 T2 int8 // 1 T3 int8 // 1 } func main() { var t Test fmt.Println(unsafe.Sizeof(t)) //3 bytes }
內存對齊
不同類型的變量占用內存大小是不一樣的,但是cpu每次讀取的內存長度是固定的(比如cpu是64位的,一次可以從內存中讀取64位的數據,即8個字節),為了cpu能高效的讀寫數據,編譯器會把各種類型的數據放在合適的地址,而不是順序的一個接一個的排放,并占用合適的長度,這就是內存對齊。每種類型的對齊值就是它的對齊邊界。
示例:
package main import ( "fmt" "unsafe" ) type Test struct { a int8 // 1 b int64 // 8 c int32 // 4 } type Test2 struct { a int8 // 1 b int32 // 4 c int64 // 8 } func main() { var t Test fmt.Println(unsafe.Sizeof(t)) // 24 var t2 Test2 fmt.Println(unsafe.Sizeof(t2))// 16 }
通過上面示例,我們可以看到兩個結構體中3個字段類型相同,當排列順序發生變化時,總的內存大小也會發生變化。下面我們來一起分析一下:
如果沒有內存對齊,那結構體各個字段在內存中是緊密排列的,如t1內存布局示意圖如下:
因為b這個字段需要8個字節,所以會有一個字節的數據排列到第2個字中。如果程序想要讀取b字段的數據,那么CPU需要兩次讀取才能獲取到完整的數據,這樣就會影響了程序的性能。
所以,為了能讓CPU減少一次獲取的時間,Go編譯器會幫你把struct結構體做數據的對齊,以便CPU可以一次將該數據從內存中讀取出來。重新排列后內存布局結構示意圖如下:
其中有13個字節是真正存儲數據的,而灰色的11個字節則是為了對齊而填充上的,不存儲任何數據,所以才會比沒有對齊排列時多出11個字節。
雖然通過對齊填充的方式提高了CPU讀寫數據的效率,但是這些填充內存確實有點浪費空間,那有沒有辦法既可以既可以做到內存對齊保證CPU讀寫效率又能減少浪費內存空間呢?
那就是調整struct字段的順序,我們在來看一下t2結構體的字段內存布局結構示意圖如下:
這樣重新排列后,只占了16個字節,比上面那種方式少了8個字節。由此可知,對結構體字段的重新排列會讓結構體更節省內。
總結
本篇文章我們一起學習了Go 語言中的內存對齊,主要內容如下:
- 結構體是占用一塊連續的內存,一個結構體變量的大小是由結構體中的字段決定。
- unsafe.Sizeof(x) 返回了變量x的內存占用大小。
- 兩個結構體,即使包含變量類型的數量相同,但是位置不同,占用的內存大小也不同,由此引出了內存對齊。
- 對結構體字段的重新排列會讓結構體更節省內。
原文鏈接:https://juejin.cn/post/7156141293188415518
相關推薦
- 2022-09-15 利用Anaconda創建虛擬環境的全過程_python
- 2022-07-21 OSPF的路由策略和流量抓取
- 2022-11-05 WPF+ASP.NET?SignalR實現后臺通知功能的示例代碼_C#教程
- 2022-03-15 3 Segmentation fault (core dumped) ./a.out Exited
- 2023-07-13 css 為什么要清除浮動
- 2022-09-06 python?留一交叉驗證的實例_python
- 2022-09-06 Python利用contextvars實現管理上下文變量_python
- 2023-04-24 React組件與事件的創建使用教程_React
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支