1. 程式人生 > >C++中什麼是記憶體對齊?

C++中什麼是記憶體對齊?

以下資料是我從別人的文章抽取出來的,我認為比較有利於理解。加上一點我的理解

 

 

接下來我們好好討論一下記憶體對齊的作用

  1.平臺原因(移植原因):不是所有的硬體平臺都能訪問任意地址上的任意資料,某些硬體平臺只能在某些地址處取某些特定型別的資料,否則丟擲硬體異常

  2.硬體原因:經過記憶體對齊之後,CPU的記憶體訪問速度大大提升。具體原因接下來解釋

圖一:

我們普通程式設計師心中的記憶體印象,由一個個位元組組成,但是CPU卻不是這麼看待的

圖二:

cpu把記憶體當成是一塊一塊的,塊的大小可以是2,4,8,16 個位元組,因此CPU在讀取記憶體的時候是一塊一塊進行讀取的,塊的大小稱為(memory granularity)記憶體讀取粒度。

我們再來看看為什麼記憶體不對齊會影響讀取速度?

    假設CPU要讀取一個4位元組大小的資料到暫存器中(假設記憶體讀取粒度是4),分兩種情況討論:

           1.資料從0位元組開始

        2.資料從1位元組開始

解析:當資料從0位元組開始的時候,直接將0-3四個位元組完全讀取到暫存器,結算完成了。

        當資料從1位元組開始的時候,問題很複雜,首先先將前4個位元組讀到暫存器,並再次讀取4-7位元組的資料進暫存器,接著把0位元組,4,6,7位元組的資料剔除,最後合併1,2,3,4位元組的資料進暫存器,對一個記憶體未對齊的暫存器進行了這麼多額外操作,大大降低了CPU的效能。

     但是這還屬於樂觀情況,上文提到記憶體對齊的作用之一是平臺的移植原因,因為只有部分CPU肯幹,其他部分CPU遇到未對齊邊界就直接罷工了。

參考圖片:

 上面的兩幅圖已經說得很清楚了,如果不記憶體對齊會有什麼後果。假如一個int型別的數,它一開始就存在0~3號記憶體中,由於我們的cpu是整塊整塊地進行資料讀取,那麼cpu就能直接將這塊資料取出來。

那如果在1~4號呢,那麼cpu就得先把兩塊記憶體取出來,將0~3號記憶體的1~3位取出來,然後再將4號的那一位取出來,存入暫存器中。這樣子就影響了效率。那麼我們乾脆浪費空間,也要讓cpu能夠一次就取出來。這就是記憶體對齊。

       接下來說說記憶體對齊的計算方法。

#include<iostream>
using namespace std;
struct A{
    char a;
    int b;
    short c;
};

struct B{
    short c;
    char a;
    int b;
};
int main(){
    A x;
    B y;
        cout<<endl;
    int *u=(int *)&x.a;
    int *t=(int *)&y.a;
    x.a='a';x.b=1;x.c=1;
    y.a='a';y.b=1;y.c=1;
    cout<<u<<endl;
    cout<<&x.b<<endl;
    cout<<&x.c<<endl;
    cout<<&y.c<<endl;
    cout<<t<<endl;
    cout<<&y.b<<endl;
    cout<<"sizeof(A): " <<sizeof(A)<<endl;
    cout<<"sizeof(B): " <<sizeof(B)<<endl;
    return 0;
}

  以下是輸出結果

我們以A為例子分析:

我在windows和Linux平臺測試了,兩個平臺的#pragma pack()都應該是4。

對結構體的各成員來說,第一個成員位於偏移量為0的位置,之後的資料成員偏移量必須是   min(#pragma pack(),該資料成員自身長度)   的倍數。因為char為第一個成員,所以其偏移量為0,int為第二個成員,其偏移量為min(4,4)=4;在下面的圖中,地址為4的倍數就是04了,所以int從這裡開始。接著是short,偏移量為min(4,2)=2;偏移量為2的倍數的就是8,所以從08開始。由於結構沒有成員了,那麼也會湊夠一個#pragma pack()。即一直到11這個位置。

假如你在short 後面加一個或者兩個char,長度也仍然為12

 以上內容來自      :https://www.cnblogs.com/jijiji/p/4854581.html