ncnn中內(nèi)存對(duì)齊
在ncnn源碼net.cpp中,int Net::load_param(const unsigned char* _mem)函數(shù)中你可以看到這么一段代碼:
if ((unsigned long)_mem & 0x3)
{
// reject unaligned memory
fprintf(stderr, "memory not 32-bit aligned at %p\n", _mem);
return -1;
}
將指針地址和0x3進(jìn)行位與,目的其實(shí)是判斷指針地址是不是4字節(jié)對(duì)齊的,主要的原因是不對(duì)齊,cpu讀取的效率會(huì)變低,具體舉例就是本來只需要一次讀取的可能需要兩次讀取了。
什么是內(nèi)存對(duì)齊
cpu在讀取內(nèi)存時(shí)是一塊一塊進(jìn)行讀取的,塊的大小可以是2,4,8,16(總之是2的倍數(shù))。舉例來說:如果一個(gè)變量int 的起始地址偏移是1,那么CPU要取這個(gè)地址上的數(shù)據(jù),需要取兩次。如圖,cpu按四字節(jié)讀取,第一次讀取0x0 ~ 0x3,

cpu第二次讀取0x4 ~ 0x7,這時(shí)cpu才能讀到這個(gè)int的值。

如果內(nèi)存對(duì)齊了呢,就如下只需一次讀?。?br>

typedef struct {
int a; //4字節(jié)
double b; //8字節(jié)
short c; //2字節(jié)
}A;
typedef struct {
int a; //4字節(jié)
short b; //2字節(jié)
double c; //8字節(jié)
}B;
上面兩個(gè)結(jié)構(gòu)體,理論上來說它們是一樣大小的,但是當(dāng)我們sizeof(A)=24,sizeof(B)=16。分析一下:對(duì)結(jié)構(gòu)體A來說,a占4個(gè)字節(jié),占從0 ~ 3的字節(jié),b是double類型占8個(gè)字節(jié),占從8 ~ 15的字節(jié),c占兩個(gè)字節(jié),從16 ~ 17的字節(jié)。 對(duì)結(jié)構(gòu)體B來說,a占4個(gè)字節(jié),從0 ~ 3,b占兩個(gè)字節(jié)從4 ~ 6;c占8個(gè)字節(jié)從8 ~ 15。當(dāng)然上面的分析是針對(duì)gcc編譯器的,不同的編譯器有不同的對(duì)齊規(guī)則。
內(nèi)存對(duì)齊規(guī)則
1、 對(duì)于結(jié)構(gòu)的各個(gè)成員,第一個(gè)成員位于偏移為0的位置,以后每個(gè)數(shù)據(jù)成員的偏移量必須是min(#pragma pack()指定的數(shù),這個(gè)數(shù)據(jù)成員的自身長(zhǎng)度) 的倍數(shù)。
2、 在數(shù)據(jù)成員完成各自對(duì)齊之后,結(jié)構(gòu)(或聯(lián)合)本身也要進(jìn)行對(duì)齊,對(duì)齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長(zhǎng)度中,比較小的那個(gè)進(jìn)行。
3、 必須是2的整數(shù)倍