關於記憶體對齊

2021-06-05 22:28:00 字數 3035 閱讀 9990

首先由乙個程式引入話題: 1

//環境:

vc6 + windows sp2

2//程式13

#include 45

using

namespace

std;67

struct

st1 8;

1314

struct

st215;20

21int

main()

2227

程式的輸出結果為:

sizeof(st1) is 12 

sizeof(st2) is 8 

問題出來了,這兩個一樣的結構體,為什麼

sizeof

的時候大小不一樣呢?

本文的主要目的就是解釋明白這一問題。

記憶體對齊,正是因為記憶體對齊的影響,導致結果不同。

對於大多數的程式設計師來說,記憶體對齊基本上是透明的,這是編譯器該幹的活,編譯器為程式中的每個資料單元安排在合適的位置上,從而導致了相同的變數,不同宣告順序的結構體大小的不同。

那麼編譯器為什麼要進行記憶體對齊呢?程式

1中結構體按常理來理解

sizeof(st1)

和sizeof(st2)

結果都應該是7,

4(int) + 2(short) + 1(char) = 7 

。經過記憶體對齊後,結構體的空間反而增大了。

在解釋記憶體對齊的作用前,先來看下記憶體對齊的規則:

1、對於結構的各個成員,第乙個成員位於偏移為

0的位置,以後每個資料成員的偏移量必須是

min(#pragma pack()

指定的數,這個資料成員的自身長度

) 的倍數。

2、在資料成員完成各自對齊之後,結構

(或聯合

)本身也要進行對齊,對齊將按照

#pragma pack

指定的數值和結構

(或聯合

)最大資料成員長度中,比較小的那個進行。

#pragma pack(n) 

表示設定為

n位元組對齊。

vc6預設

8位元組對齊

以程式1為例解釋對齊的規則:

st1 

:char

佔乙個位元組,起始偏移為0 ,

int 佔4

個位元組,

min(#pragma pack()

指定的數,這個資料成員的自身長度

) = 4

(vc6預設8

位元組對齊),所以

int按

4位元組對齊,起始偏移必須為

4的倍數,所以起始偏移為4,在

char

後編譯器會新增

3個位元組的額外位元組,不存放任意資料。

short佔2

個位元組,按

2位元組對齊,起始偏移為

8,正好是

2的倍數,無須新增額外位元組。到此規則

1的資料成員對齊結束,此時的記憶體狀態為:

o***|oooo|oo

0123 4567 89 

(位址) (

x表示額外新增的位元組)

共佔10個位元組。還要繼續進行結構本身的對齊,對齊將按照

#pragma pack

指定的數值和結構

(或聯合

)最大資料成員長度中,比較小的那個進行,

st1結構中最大資料成員長度為

int,佔

4位元組,而預設的

#pragma pack 

指定的值為

8,所以結果本身按照

4位元組對齊,結構總大小必須為

4的倍數,需新增

2個額外位元組使結構的總大小為

12 。此時的記憶體狀態為:

o***|oooo|ooxx

0123 4567 89ab  

(位址)

到此記憶體對齊結束。

st1占用了

12個位元組而非

7個位元組。

st2 

的對齊方法和

st1相同,讀者可自己完成。

記憶體對齊的主要作用是:

1、平台原因

(移植原因

):不是所有的硬體平台都能訪問任意位址上的任意資料的;某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。

2、效能原因:經過記憶體對齊後,

cpu的記憶體訪問速度大大提公升。具體原因稍後解釋。

圖一:這是普通程式設計師心目中的記憶體印象,由乙個個的位元組組成,而

cpu並不是這麼看待的。

圖二:cpu

把記憶體當成是一塊一塊的,塊的大小可以是2,

4,8,

16位元組大小,因此

cpu在讀取記憶體時是一塊一塊進行讀取的。塊大小成為

memory access granularity

(粒度) 

本人把它翻譯為「記憶體讀取粒度」 。

假設cpu要讀取乙個

int型

4位元組大小的資料到暫存器中,分兩種情況討論:

1、資料從

0位元組開始

2、資料從

1位元組開始

再次假設記憶體讀取粒度為4。

圖三:當該資料是從

0位元組開始時,很

cpu只需讀取記憶體一次即可把這

4位元組的資料完全讀取到暫存器中。

當該資料是從

1位元組開始時,問題變的有些複雜,此時該

int型資料不是位於記憶體讀取邊界上,這就是一類記憶體未對齊的資料。

圖四:此時

cpu先訪問一次記憶體,讀取

0—3位元組的資料進暫存器,並再次讀取

4—5位元組的資料進暫存器,接著把

0位元組和6,

7,8位元組的資料剔除,最後合併1,

2,3,

4位元組的資料進暫存器。對乙個記憶體未對齊的資料進行了這麼多額外的操作,大大降低了

cpu效能。

這還屬於樂觀情況了,上文提到記憶體對齊的作用之一為平台的移植原因,因為以上操作只有有部分

cpu肯幹,其他一部分

cpu遇到未對齊邊界就直接罷工了。

關於記憶體對齊

資料傳送到網路板的資料報大小根本不是實際控制數 據包的大小 這時我才想起乙個人,stanley b.lippman,他寫的那 一本書 inside object modale 曾經提過這樣的事 情,編譯器為了提高cpu的效率,會對struct 的結構進行優化,利用sizeof 可以得出不同的計算機上...

關於記憶體對齊

早上看了乙個貼的面試題,struct st int i short s char c sizeof struct st 是多少?int 4,short 2,char 1,但是sizeof st 是8。這個就是記憶體對齊 再來看個例子 struct strt1 strt1 s1 假設s1.c1位址為0...

關於記憶體對齊

資料傳送到網路板的資料報大小根本不是實際控制資料報的大小 這時我才想起乙個人,stanley b.lippman,他寫的那一本書 inside object modale 曾經提過這樣的事情,編譯器為了提高cpu的效率,會對struct 的結構進行優化,利用sizeof 可以得出不同的計算機上對 s...