2012-04-25 80 views

回答

7

好問題。考慮這個假設類型:

struct A { 
    int n; 
    bool flag; 
}; 

所以,A類型的對象,應該採取五個字節(四爲INT加上一個用於布爾),但實際上它需要八。爲什麼?如果使用這樣的類型

答案是看出:

const size_t N = 100; 
A a[N]; 

如果每個A只有五個字節,然後a[0]會保持一致,但a[1]a[2]和大多數其他元素不會。

但爲什麼對齊甚至重要?有幾個原因,所有硬件相關。一個原因是最近/經常使用的內存被緩存在CPU芯片上的高速緩存行中以用於快速訪問。比緩存行更小的對齊對象總是適合單行(但請參閱下面附加的有趣註釋),但未對齊的對象可能跨越兩行,浪費緩存。

實際上甚至有更基本的硬件原因,與字節可尋址數據在32位或64位數據總線上傳輸的方式有關,這與緩存行很相似。不僅如此,錯位會阻塞總線,導致額外的提取(由於像以前一樣跨越),但它也會強制寄存器在進入時轉移字節。更糟糕的是,錯位容易導致優化邏輯混淆(至少,英特爾的優化手冊說它的確如此,儘管我對這最後一點沒有個人認識)。所以,從性能的角度來看,錯位是非常糟糕的。

由於這些原因,通常浪費填充字節是值得的。

更新:下面的評論都是有用的。我推薦他們。

+1

*小於緩存行的對齊對象始終適合單行,但未對齊對象可能跨過兩行*> **否**。是否對齊可能跨越兩條線。 – 2012-04-25 07:10:40

+1

@MatthieuM。,實際上是和不。高速緩存行大小是最大數據大小和任何其他基本類型的倍數。因此,所有(呃,大多數)對齊的_native_類型自然會在單個緩存行內。考慮任何1,2,4,8,16字節對齊的類型將自動對齊,以適應64或128字節的高速緩存行。如果情況並非如此,系統本質上將不可用。 – 2012-04-25 07:25:19

+1

@ edA-qamort-ora-y:當然,但是一個基本類型複合的對象可能很容易跨越兩條線。即使它更小。假設一個64字節的行,我可以有一個大小爲48字節的對象,並且在這樣的對象的表中,至少有兩個會跨越兩個緩存行。 – 2012-04-25 08:17:30

0

由於虛擬尋址的。

「......一個頁面大小的邊界上對齊頁通過在地址替換 較高位,而不是做複雜的算術讓 硬件映射虛擬地址到物理地址。」

順便說一句,我發現維基百科頁面寫得很好。

+1

不相關.... – 2012-04-25 07:11:27

0

如果CPU的寄存器大小是32位,那麼它可以通過單個彙編指令獲取位於32位邊界的存儲器。抓取32位比較慢,然後得到從第8位開始的字節。

順便說一句:不需要填充。你可以問結構是否包裝。

+1

包裝是特定於編譯器的,而不是語言。如果處理未對齊的加載和存儲的CPU /內核支持不存在或未打開,包裝將在RISC機器上爆炸。只爲速度對準;對某些機器來說這是一個很難的要求。 – Kaz 2012-04-25 04:36:55

1

根據硬件的不同,對齊可能是必要的,或者只是幫助加快執行速度。

有一定數量的處理器(我相信ARM),其中未對齊的訪問會導致硬件異常。乾淨利落。

儘管典型的x86處理器更寬鬆,但在訪問未對齊的基本類型時仍存在一定的代價,因爲處理器在能夠操作它之前必須做更多的工作才能將這些位帶入寄存器。儘管如此,編譯器通常會提供特定的屬性/編譯指示,但仍需要包裝