內存對齊,memory alignment.為了提高程序的性能,數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的內存,處理器需要作兩次內存訪問;然而,對齊的內存訪問僅需要一次訪問。
內存對齊一般講就是cpu access memory的效率(提高運行速度)和准確性(在一些條件下,如果沒有對齊會導致數據不同步現象).依賴cpu,平台和編譯器的不同.一些cpu要求較高(這句話說的不准確,但是確實依賴cpu的不同),而有些平台已經優化內存對齊問題,不同編譯器的對齊模數不同.總的來說內存對齊屬於編譯器的問題.
一般情況下不需要理會內存對齊問題,內存對齊是編譯器的事情.但碰到一些問題上還是需要理解這個概念.畢竟c/c++值直接操作內存的語言.需要理解程序在內存中的分布和運行原理.
總之一句話就是:不要讓代碼依賴內存對齊.
詳細帖子見http://bbs.csdn.net/topics/30388330
成員的內存分配規律:從結構體的首地址開始向後依次為每個成員尋找第一個滿足條件的首地址x,該條件是x % N = 0,並且整個結構的長度必須為各個成員所使用的對齊參數中最大的那個值的最小整數倍,不夠就補空字節。
結構體中所有成員的對齊參數N的最大值稱為結構體的對齊參數。
VC++6.0中n 默認是8個字節,可以修改這個設定的對齊參數
也可以采用指令:#pragma pack(xx)控制.
1.基礎例子
#pragma pack(n) struct A { char c; //1byte double d; //8byte short s; //2byte int i; //4byte }; int main(int argc, char* argv[]) { A strua; printf("%len:d\n",sizeof(A)); printf("%d,%d,%d,%d",&strua.c,&strua.d,&strua.s,&strua.i); return 0; }
1)n設置為8byte時
結果:len:24,
1245032,1245040,1245048,1245052
內存中成員分布如下:
strua.c分配在一個起始於8的整數倍的地址1245032(為什麼是這樣讀者先自己思考,讀完就會明白),接下來要在strua.c之後分配strua.d,由於double為8字節,取N=min(8,8),8字節來對齊,所以從strua.c向後找第一個能被8整除的地址,所以取1245032+8得1245040, strua.s 為2byte小於參數n,所以N=min(2,8),即N=2,取2字節長度對齊,所以要從strua.d後面尋找第一個能被2整除的地址來存儲strua.s,由於strua.d後面的地址為1245048可以被2整除,所以strua.s緊接著分配,現在來分配strua.i,int為4byte,小於指定對齊參數8byte,所以N=min(4,8)取N=4byte對齊,strua.s後面第一個能被4整除地址為1245048+4,所以在1245048+4的位置分配了strua.i,中間補空,同時由於所有成員的N值的最大值為8,所以整個結構長度為8byte的最小整數倍,即取24byte其余均補0.
於是該結構體的對齊參數就是8byte。
2)當對齊參數n設置為16byte時,結果同上,不再分析
3)當對齊參數設置為4byte時
上例結果為:Len:20
1245036,1245040,1245048,1245052
內存中成員分布如下:
Strua.c起始於一個4的整數倍的地址,接下來要在strua.c之後分配strua.d,由於strua.d長度為8byte,大於對齊參數4byte,所以N=min(8,4)取最小的4字節,所以向後找第一個能被4整除的地址來作為strua.d首地址,故取1245036+4,接著要在strua.d後分配strua.s,strua.s長度為2byte小於4byte,取N=min(2,4)2byte對齊,由於strua.d後的地址為1245048可以被2
整除,所以直接在strua.d後面分配,strua.i的長度為4byte,所以取N=min(4,4)4byte對齊,所以從strua.s向後找第一個能被4整除的位置即1245048+4來分配和strua.i,同時N的最大值為4byte,所以整個結構的長度為4byte的最小整數倍20byte
4)當對齊參數設置為2byte時
上例結果為:Len:16
1245040,1245042,1245050,1245052
Strua.c分配後,向後找一第一個能被2整除的位置來存放strua.d,依次類推
5)1byte對齊時:
上例結果為:Len:15
1245040,1245041,1245049,1245051
此時,N=min(sizeof(成員),1),取N=1,由於1可以整除任何整數,所以各個成員依次分配,沒有間空.
6)當結構體成員為數組時,並不是將整個數組當成一個成員來對待,而是將數組的每個元素當一個成員來分配,其他分配規則不變,如將上例的結構體改為:
struct A
{
char c; //1byte
double d; //8byte
short s; //2byte
char szBuf[5];
};
對齊參數設置為8byte,則,運行結果如下:
Len:24
1245032,1245040,1245048,1245050
Strua 的s分配後,接下來分配Strua 的數組szBuf[5],這裡要單獨分配它的每個元素,由於是char類型,所以N=min(1,8),取N=1,所以數組szBuf[5]的元素依次分配沒有間隙。
看完上述的例子,基本分配的規律和方法應該已經知道.下面主要說明數組,嵌套結構體,指針時的一些內存對齊問題.
最重要的是自己寫程序證明.
#include#include using namespace std; #pragma pack(8) struct Args { char ch; double d; short st; char rs[9]; int i; } args; struct Argsa { char ch; Args test; char jd[10]; int i; }arga; int main() { // cout < 輸出結果: Args:32
10
Argsa:56
Argsa:12
Argsa:32
struct Args長度32 struct Argsa長度:56. 改成#pragma pack (16)結果一樣. 這個例子證明了三點: 對齊長度長於struct中的類型長度最長的值時,設置的對齊長度等於無用. 數組對齊的長度是按照數組成員類型長度來比對的. 嵌套的結構體中,所包含的結構體的對齊長度是結構體的對齊長度.
3.指針.主要是因為32位和64位機尋址上 測試環境同2.(64位系統)#include#include #pragma pack(4) using namespace std; struct Args { int i; double d; char *p; char ch; int *pi; }args; int main() { cout<<"args length:"<
設置pack為4時: args length:32
8
4
設置pack為8時: args length:40
8
8
看了上述內容,應該能分析出來為什麼是這個結果.這裡不詳細描述.
3.不同編譯器中內存對齊
VC 6.0上是8 byte
gcc 默認是8byte.測試版本gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 g++默認是8byte.測試版本g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 但查閱的資料說是gcc 默認是4,且不支持pragma參數設定.測試的時候gcc默認對齊為8byte且,支持pragma參數. 測試過兩個不同的例子,結果相同.
4.什麼時候需要進行內存對齊.
一般情況下都不需要對編譯器進行的內存對齊規則進行修改,因為這樣會降低程序的性能,除非在以下兩種情況下:
(1)這個結構需要直接被寫入文件;
(2)這個結構需通過網絡傳給其他程序;
5.不足之處.
沒有類方面的內容.
位段問題.這個問題有點復雜
具體應用的案例.
歡迎拍磚,不喜口水!
參考: http://bbs.csdn.net/topics/30388330
http://blog.csdn.net/daliaojie/article/details/7516099
http://blog.csdn.net/cuibo1123/article/details/2547442
http://blog.csdn.net/mbh_1991/article/details/10241785
http://blog.csdn.net/xing_hao/article/details/6678048
http://developer.51cto.com/art/201002/183652.htm
http://m.oschina.net/blog/167508?p=2
http://blog.csdn.net/acorld/article/details/9104579
http://blog.csdn.net/anonymalias/article/details/8743857
http://www.dewen.org/q/5835/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E8%BF%9B%E8%A1%8C%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%EF%BC%9F?sort=active
http://bbs.ednchina.com/BLOG_ARTICLE_92132.HTM
http://stackoverflow.com/questions/12881179/why-is-memory-alignment-required
http://stackoverflow.com/questions/381244/purpose-of-memory-alignment
http://blog.csdn.net/linuxblack125125/article/details/7849743