說(shuō)到內(nèi)存對(duì)齊,很多人都知道是怎么回事。但是內(nèi)存對(duì)齊該娘不是本文的重點(diǎn),本文的重點(diǎn)是內(nèi)存對(duì)齊有什么好處。
CPU訪問(wèn)某個(gè)數(shù)據(jù)時(shí),要求其存儲(chǔ)地址必須是相應(yīng)數(shù)據(jù)類型的自然邊界。對(duì)于存儲(chǔ)地址不在其相應(yīng)類型自然邊界的數(shù)據(jù),不支持非對(duì)齊數(shù)據(jù)訪問(wèn)的CPU,會(huì)導(dǎo)致CPU異常;即使是支持非對(duì)齊數(shù)據(jù)訪問(wèn)的CPU,也會(huì)嚴(yán)重影響程序效率。
假設(shè)非對(duì)齊訪問(wèn)出現(xiàn)在位于操作系統(tǒng)之上的進(jìn)程,且CPU不支持非對(duì)齊數(shù)據(jù)訪問(wèn),那么對(duì)于出現(xiàn)CPU異常的情況,可能操作系統(tǒng)會(huì)對(duì)其進(jìn)行處理,(1)將所需要的數(shù)據(jù)裝載,并返回,或者說(shuō)(2)直接讓進(jìn)程死掉。情形(2)不需要多做解釋;對(duì)情況(1)來(lái)說(shuō),非對(duì)齊訪問(wèn)每次都要進(jìn)入異常處理程序,相比于一條指令直接拿到數(shù)據(jù),效率極其低下。
假設(shè)非對(duì)齊訪問(wèn)出現(xiàn)在直接位于硬件之上的進(jìn)程,且CPU不支持非對(duì)齊數(shù)據(jù)訪問(wèn),那么對(duì)于出現(xiàn)CPU異常的情況來(lái)說(shuō),基本上的直觀反應(yīng)是進(jìn)程退出并出現(xiàn)堆棧信息。
現(xiàn)在假設(shè)有一個(gè)8字節(jié)數(shù)據(jù)如下,|表示數(shù)據(jù)開(kāi)始位置,|-|表示自然邊界
|-|BBBBB|BBB|-|BBBBB|BBB
其前三字節(jié)為前一個(gè)對(duì)齊的八字節(jié)數(shù)據(jù)的后三字節(jié),其后五字節(jié)為后一個(gè)對(duì)齊的八字節(jié)數(shù)據(jù)的前五字
對(duì)于不支持非對(duì)齊裝載指令的CPU來(lái)說(shuō),要裝載這樣的一個(gè)數(shù)據(jù),需要先裝載前一個(gè)八字節(jié)數(shù)據(jù),再裝載后一個(gè)八字節(jié)數(shù)據(jù),然后將前一個(gè)八字節(jié)數(shù)據(jù)的后三字節(jié)與后一個(gè)八字節(jié)數(shù)據(jù)的前五字節(jié)數(shù)據(jù)合并才能得到結(jié)果,與對(duì)齊數(shù)據(jù)的訪問(wèn)相比,多了一個(gè)裝載指令以及相關(guān)合并指令的開(kāi)銷,一般來(lái)說(shuō),在忽視緩存未命中的情況下,裝載指令的執(zhí)行與得到結(jié)果之間是存在額外開(kāi)銷的,因此這個(gè)差別是很大的,何況上邊說(shuō)的,假設(shè)是在操作系統(tǒng)對(duì)CPU異常進(jìn)行處理時(shí)為其加載數(shù)據(jù),那么異常處理程序的開(kāi)銷可能更大;對(duì)非對(duì)齊數(shù)據(jù)的寫(xiě)入時(shí)也需要額外的加載,合并操作。
即使對(duì)于支持非對(duì)齊數(shù)據(jù)加載的CPU,依然會(huì)極大的影響效率,差別只是它省略掉了CPU異常處理過(guò)程。
再進(jìn)一層,假設(shè)之前描述的非對(duì)齊數(shù)據(jù)剛好橫跨兩個(gè)cache line,而且這兩個(gè)cache line至少有一個(gè)不在cache中(雖然對(duì)齊數(shù)據(jù)也會(huì)存在未命中,但是與非對(duì)齊相比,它不會(huì)橫跨兩個(gè)cache line),那么這個(gè)訪問(wèn)效率絕對(duì)不是多幾十條指令的問(wèn)題了。
因此,內(nèi)存不對(duì)齊的壞處不是浪費(fèi)內(nèi)存,因?yàn)榧词刮覍?xiě)一個(gè)隨便在不同位置放置不同大小的數(shù)據(jù)結(jié)構(gòu)時(shí),只要告訴編譯器說(shuō)必須按照一字節(jié)對(duì)齊,編譯器編譯時(shí)肯定按照我的意愿不浪費(fèi)一個(gè)字節(jié)的內(nèi)存。編譯器默認(rèn)按照自然邊界對(duì)齊,是因?yàn)樗笮?,保證程序的正常運(yùn)行(因?yàn)榉菍?duì)齊訪問(wèn)可能導(dǎo)致進(jìn)程退出)。我們對(duì)結(jié)構(gòu)體的組織的調(diào)整是為了節(jié)約內(nèi)存,而調(diào)整的規(guī)則就是按照內(nèi)存對(duì)齊來(lái)安插數(shù)據(jù)。
每個(gè)特定平臺(tái)上的編譯器都有自己的默認(rèn)“對(duì)齊系數(shù)”(也叫對(duì)齊模數(shù))。程序員可以通過(guò)預(yù)編譯命令#pragma pack(n),n=1,2,4,8,16來(lái)改變這一系數(shù),其中的n就是你要指定的“對(duì)齊系數(shù)”。
規(guī)則:
1、數(shù)據(jù)成員對(duì)齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員的對(duì)齊按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中,比較小的那個(gè)進(jìn)行。
2、結(jié)構(gòu)(或聯(lián)合)的整體對(duì)齊規(guī)則:在數(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、結(jié)合1、2可推斷:當(dāng)#pragma pack的n值等于或超過(guò)所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,這個(gè)n值的大小將不產(chǎn)生任何效果。
Win32平臺(tái)下的微軟C編譯器的對(duì)齊策略:
1)結(jié)構(gòu)體變量的首地址是其最長(zhǎng)基本類型成員的整數(shù)倍;
備注:編譯器在給結(jié)構(gòu)體開(kāi)辟空間時(shí),首先找到結(jié)構(gòu)體中最寬的基本數(shù)據(jù)類型,然后尋找內(nèi)存地址能是該基本數(shù)據(jù)類型的整倍的位置,作為結(jié)構(gòu)體的首地址。將這個(gè)最寬的基本數(shù)據(jù)類型的大小作為上面介紹的對(duì)齊模數(shù)。
2)結(jié)構(gòu)體每個(gè)成員相對(duì)于結(jié)構(gòu)體首地址的偏移量(offset)都是成員大小的整數(shù)倍,如有需要編譯器會(huì)在成員之間加上填充字節(jié)(internal adding);
備注:為結(jié)構(gòu)體的一個(gè)成員開(kāi)辟空間之前,編譯器首先檢查預(yù)開(kāi)辟空間的首地址相對(duì)于結(jié)構(gòu)體首地址的偏移是否是本成員的整數(shù)倍,若是,則存放本成員,反之,則在本成員和上一個(gè)成員之間填充一定的字節(jié),以達(dá)到整數(shù)倍的要求,也就是將預(yù)開(kāi)辟空間的首地址后移幾個(gè)字節(jié)。
3)結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,如有需要,編譯器會(huì)在最末一個(gè)成員之后加上填充字節(jié)。
備注:
a、結(jié)構(gòu)體總大小是包括填充字節(jié),最后一個(gè)成員滿足上面兩條以外,還必須滿足第三條,否則就必須在最后填充幾個(gè)字節(jié)以達(dá)到本條要求。
b、如果結(jié)構(gòu)體內(nèi)存在長(zhǎng)度大于處理器位數(shù)的元素,那么就以處理器的倍數(shù)為對(duì)齊單位;否則,如果結(jié)構(gòu)體內(nèi)的元素的長(zhǎng)度都小于處理器的倍數(shù)的時(shí)候,便以結(jié)構(gòu)體里面最長(zhǎng)的數(shù)據(jù)元素為對(duì)齊單位。
4) 結(jié)構(gòu)體內(nèi)類型相同的連續(xù)元素將在連續(xù)的空間內(nèi),和數(shù)組一樣。
總結(jié):
1、平臺(tái)原因(移植原因):不是所有的硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
2、性能原因:數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。原因在于,為了訪問(wèn)未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問(wèn);而對(duì)齊的內(nèi)存訪問(wèn)僅需要一次訪問(wèn)。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
新聞名稱:為什么存在內(nèi)存對(duì)齊-創(chuàng)新互聯(lián)
文章URL:http://jinyejixie.com/article34/decope.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、ChatGPT、定制網(wǎng)站、網(wǎng)站策劃、響應(yīng)式網(wǎng)站、動(dòng)態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容