接觸記憶體對齊這個概念,也有三四年了。不過由于我工作後一直做遊戲伺服器,都是在x86架構的機子上寫代碼,也沒怎麼注意記憶體對齊。使用最多的估計也就是面試時經常問結構體大小。最近在寫自己伺服器架構的二進流讀寫子產品時,整理了下這方面的内容。本方不會涉及基本概念。
記憶體對齊隻是指資料存儲在記憶體時的起始位址是否是某個值的整數倍。如果隻是放在記憶體中,是否對齊本身并沒有什麼問題。問題是讀取、寫入的時候。通路一個不對齊的資料(unaligned memory access)可能會導緻程式運作效率慢,結果出錯,甚至是程式當掉。那這些情況是怎麼出現的呢?
我們都知道,程式最終都是以CPU指令來運作的。參考:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html,我們知道ARM CPU有下面幾條指令:
LDRB/STRB - address must be byte aligned
LDRH/STRH - address must be 2-byte aligned
LDR/STR - address must be 4-byte aligned
LDRB/STRB位元組加載、存儲指令
LDRH/STRH半字(即2byte,不是半位元組)加載、存儲指令
LDR/STR 字加載、存儲指令
也就是說,當我們從記憶體中存取資料時,要調用上面的指令。而這些指令在設計時,較老的CPU由于考慮了硬體、效率等等問題,要求通路的記憶體必須是對齊的。現在假如我聲明了一個記憶體緩沖區char *buffer[1024],系統給它配置設定的位址是0x00001000,可以看到,這個位址都是符合1、2、4位元組對齊的。接着我從網絡接收了一段資料,放到這個緩沖區裡。現在要從緩沖區裡依次取出char、int兩個類型的資料:
char ch = *buffer;
int i = *reinterpret_cast<int *>(buffer+1);
運作ch = *buffer時,由于char類型的大小是1位元組,CPU将調用LDRB指令,這時将檢測buffer是否按1byte對齊。這裡當然是對齊的,是以指令運作正常。
運作i = *reinterpret_cast<int *>(buffer+1)時,由于int類型大小是4位元組,CPU将調用LDR指令,這時檢測buffer+1(0x00001001)是否按4byte對齊,結果發現不對齊,CPU将報錯,程式中止。
而安全的做法是這樣的:
memcpy( &ch,buffer,1 );
memcpy( &i,buffer+1,4 );
你可能會問,使用memcpy,buffer+1的位址也是不對齊的,為什麼就安全了呢?就像我上面所說的,資料在記憶體中存放時,是否對齊并不重要,重要的是你怎樣去通路它。memcpy的實作本身并不簡單(你在源碼裡看到的通過while每次拷貝一個char的隻是一個例子,并不是真實的memcpy),它考慮了是否對齊。當檢測到記憶體是對齊時,memcpy調用合适的指令(比較這裡拷貝一個int,就調用LDR),一次拷貝多個位元組,以提高效率。當檢測到不對齊時,先調用LDRB遂個位元組拷貝,直到對齊部分後再調用合适的指令拷貝。是以,在上面的例子中,它是先調用LDRB的,因為LDRB是按1byte對齊(所有的記憶體都按這個對齊),是以不會觸發報錯。但效率就要慢一點了,畢竟要拷貝幾次。
記憶體對齊本身對程式員來說是透明的,即程式員該取變量就取變量,該存就存,編譯程式時編譯器會把變量按本身的平台進行對齊。況且現在的CPU都很進階,别說伺服器,桌上型電腦的CPU,ARM 7以上應該也支援記憶體不對齊通路了。但如果你要寫一個記憶體池(boost的ordered_pool有對齊的例子),或者使用了reinterpret_cast這種對記憶體直接進行操作的函數,這方面還是要注意一下,即使CPU支援,效率也會受到影響。
我在很多項目中,發現這樣的寫法:
#pragma pack(push,1)
struct NetPack
{
//...
};
#pragma pack(pop)
這是強制把這個結構體按1byte對齊,當有網絡資料過來,直接memcpy整個結構體就可以。有趣的時,我在核心文檔裡發現這麼一段話:https://www.kernel.org/doc/Documentation/unaligned-memory-access.txt
當我們把變量強制按1byte對齊時,編譯器不會在結構體中加入任何内容來使得這個結構體符合記憶體對齊,而是産生一些額外的指令來讓他滿足目前平台的記憶體對齊,當然,效率還是受影響的。
本文轉自xsster51CTO部落格,原文連結:http://blog.51cto.com/12945177/1951667 ,如需轉載請自行聯系原作者