結構體內部儲存中的對齊問題
舉個例子
我們考慮如下的這個結構體:
struct ALIGN {
char a;
int b;
char c;
};
如果某個機器的整型值長度為4個位元組,並且它的起始儲存位置必須能夠被4整除,那麼這個結構體在記憶體中的儲存將如下圖所示:
說明:系統禁止編譯器在一個結構體的起始位置跳過幾個位元組來滿足邊界的對齊要求,因此所有結構體的起始儲存位置必須是結構體中邊界要求最嚴格的資料型別所要求的位置。因此,成員a(最左邊那個方框)必須儲存於一個能夠被4整除的地址。結構的下一個成員是一個整型值,所以它必須跳過3個位元組到達合適的邊界才能儲存。在整型值之後是最後一個字元。
如果宣告瞭相同型別的第二個變數,它的起始儲存位置也必須滿足4這個邊界,所以第一個結構體的後面還要再跳過3個位元組才能儲存第二個結構體。因此,每個結構體將佔據12個位元組的記憶體空間,但實際只使用了其中的6個,這個利用率可不是很出色。
我們可以在宣告中對結構體的成員列表重新排列,讓那些對邊界要求最嚴格的成員首先出現,對邊界要求最弱的成員最後出現。這種做法可以最大限度地減少因邊界對齊而帶來的空間損失。例如:
struct ALIGN2 {
int b;
char a;
char c;
};
它所包含的成員和前面那個結構體一樣,但它只佔用8個位元組的空間,節省了三分之一。兩個字元可以緊挨著儲存,所以只有結構體最後面需要跳過的兩個位元組被浪費。
有時,我們有充分的理由,決定不對結構體的成員進行重新排列以減少因對齊帶來的空間損失,例如:我們可能想把相關的結構體成員儲存在一起,提高程式的可維護性和可讀性。但是,如果不存在這樣的理由,結構體的成員應該根據它們的邊界需要進行重新排列,減少因邊界對齊而造成的記憶體損失。
當程式將建立幾百個甚至幾千個結構體時,減少記憶體浪費的要求就比程式的可讀性更為急迫。在這種情況下,在宣告中增加註釋可能避免可讀性方面的損失。
sizeof操作符可以得出一個結構體的整體長度,包括因邊界對齊而跳過的那些位元組。如果你必須確定結構體中某個成員的實際位置,應該考慮邊界對齊因素,可以使用offsetof巨集:
#include <stddef.h>
// 得到指定成員開始儲存的位置距離結構體開始儲存的位置偏移了幾個位元組
size_t offsetof( structName, memberName );
例如,拿之前宣告的結構體舉例:
offsetof( struct ALIGN, b )的返回值為4。
結構體資料成員對齊的意義
許多實際的計算機系統對基本型別資料在記憶體中存放的位置有限制,它們會要求這些資料的起始地址的值是某個數k的倍數,這就是所謂的記憶體對齊,而這個k則被稱為該資料型別的對齊模數(alignment modulus)。這種強制的要求一來簡化了處理器與記憶體之間傳輸系統的設計,二來可以提升讀取資料的速度。
比如這麼一種處理器,它每次讀寫記憶體的時候都從某個8的倍數的地址開始,一次讀出或寫入8個位元組的資料,假如軟體能保證double型別的資料都從8倍數地址開始,那麼讀或寫一個double型別資料就只需要一次記憶體操作。否則,我們就可能需要兩次記憶體操作才能完成這個動作,因為資料或許恰好橫跨在兩個符合對齊要求的8位元組記憶體塊上。
參考資料:
1.Kenneth A. Reek.C和指標.北京:人民郵電出版社,2008
2.http://www.cnblogs.com/motadou/archive/2009/01/17/1558438.html
相關文章
- C結構體中資料的記憶體對齊問題結構體記憶體
- C語言中結構體struct的對齊問題C語言結構體Struct
- Java HashMap原理及內部儲存結構JavaHashMap
- 資料庫內部儲存結構探索資料庫
- 結構體記憶體對齊結構體記憶體
- 利用泛型模擬棧結構實現內部鏈式儲存結構泛型
- js中的儲存問題JS
- 從 CPU 角度理解 Go 中的結構體記憶體對齊Go結構體記憶體
- Android-內部儲存和外部儲存Android
- C++ struct結構體記憶體對齊C++Struct結構體記憶體
- c 結構體記憶體對齊詳解結構體記憶體
- struct結構體大小的計算(記憶體對齊)Struct結構體記憶體
- C/C++結構體對齊測試C++結構體
- 儲存結構
- MySQL InnoDB儲存引擎體系結構MySql儲存引擎
- MySQL體系結構與儲存引擎MySql儲存引擎
- 結構體問題結構體
- MongoDB 儲存引擎與內部原理MongoDB儲存引擎
- WPS/Word中公式與文字不對齊的問題公式
- JanusGraph -- 儲存結構
- CentOS 儲存結構CentOS
- FPGA內部硬體結構簡介FPGA
- php圖的儲存結構PHP
- 深度分析C#中Array的儲存結構C#
- MySQL的varchar儲存原理:InnoDB記錄儲存結構MySql
- MySQLInnoDB儲存引擎(一):精談innodb的儲存結構MySql儲存引擎
- 【Mysql技術內幕筆記--1】--Mysql體系結構和儲存引擎MySql筆記儲存引擎
- 深度解析C#中LinkedList<T>的儲存結構C#
- 圖(Graph)——圖的儲存結構
- 儲存器的層次結構
- 【資料結構——圖和圖的儲存結構】資料結構
- Alter修改表結構對資料儲存的影響PP
- Aspose.Slides.NET 19.2 解析ppt內容儲存svg 儲存ppt內部圖片IDESVG
- 雲端計算導論 # 3 雲端儲存技術:概念、結構模型、關鍵技術、分散式資料儲存、常見儲存結構、應用與問題模型分散式
- 棧與佇列鏈式儲存結構一貨物上架問題佇列
- Redis儲存物件問題Redis物件
- Prometheus時序資料庫-磁碟中的儲存結構Prometheus資料庫
- HDU-安卓程式開發之簡單儲存/內部儲存/外部儲存 & 捉蟲安卓
- 【PHP資料結構】圖的概念和儲存結構PHP資料結構