每一種處理器都會有自己的記憶體對齊要求,這樣做的目的很大程度上是為了處理器讀取記憶體資料的效率,當然還有匯流排等因素的影響,具體的可以看一下為什麼要記憶體對齊 data alignment: straighten up and fly right ,我覺得寫得還不錯。好了,廢話不多說,接下來看一下lwip在不同平台上是如何實現記憶體對齊的。
一. 對齊的總類及本質
在lwip中,記憶體對齊分兩種:
#define lwip_mem_align(addr) ((void *)(((mem_ptr_t)(addr) + mem_alignment - 1) & ~(mem_ptr_t)(mem_alignment-1)))
2、資料占用空間大小對齊,同樣的也是使用巨集定義實現:
#define lwip_mem_align_size(size) (((size) + mem_alignment - 1) & ~(mem_alignment-1))
先不講解為什麼這麼做就可以達到記憶體對齊的目的,我們先思考一下記憶體對齊的本質要求是什麼,假如我們細心一點就會發現,其實對齊無非就是實現以下兩點要求:
a、占用的記憶體大小或者位址值最後的二進位制n位(根據對齊要求,如4位元組對齊,n取2)必須全為0。
b、若當前占用的記憶體大小或者位址值最後n位不為0,則需要向上取整。比如按照4位元組對齊要求(二進位制最後2位必須為0),當我的變數起始位址為0x03(二進位制位0b011),那麼該變數的起始位址就會對齊到0x04(二進位制位0b100)。
二. lwip對齊的實現
1.、定義對齊要求
在lwip中也是使用巨集定義來設定對齊要求,使用者可以在lwipopts.h中設定自己硬體平台上的對齊要求:
/*4位元組對齊*/
#define mem_alignment 4
2、資料占用空間大小對齊
#define lwip_mem_align_size(size) (((size) + mem_alignment - 1) & ~(mem_alignment-1))
為啥巨集定義寫成是這樣的呢,其實根據我剛剛說的對齊本質理解就比較簡單了,假定mem_alignment定義為4,size取15(二進位制位0b1111),那麼:
a、~(mem_alignment-1):其實就是~(0b100-0b001)為0b1…100,目的就是當成掩碼通過&運算將((size) + mem_alignment - 1)運算的結果後兩位取0,也就是上面對齊原理的a點。
b、((size) + mem_alignment - 1):其實是為了滿足對齊的第二點要求——向上取整。因為在第a步中,我們會二進位制的最後n位取0,為了達到向上取整的效果,必須保證經過第a步的掩碼操作後得出的對齊記憶體要大於或者等於size。根據假定size為15,經過(size) + mem_alignment - 1計算得到18(0b10010),最後經過第a不得掩碼(0x1…100)得出16(0b10000),即15向上取整對齊后位16。
3、資料起始位址對齊
#define lwip_mem_align(addr) ((void *)(((mem_ptr_t)(addr) + mem_alignment - 1) & ~(mem_ptr_t)(mem_alignment-1)))
這裡對齊的策略和資料占用空間大小對齊是一樣的,可以依據對齊的本質理解。但是注意乙個問題,在起始位址對齊時,增加了mem_ptr_t(這是移植人員定義的處理器指標型別長度,一般為u32),避免在記憶體最高位址處取出的對齊位址為非法位址,即位址溢位了,在這種情況,增加mem_ptr_t變數可以使得出的對齊位址重新回到0x0處。
4、保證最低的空間大小
最後一點想說的就是,在lwip中長出現需要保證申請的空間必須在對齊的要求上達到最低的大小。比如下面這一段構造記憶體池的**
static u8_t memp_memory[mem_alignment - 1
#define lwip_mempool(name,num,size,desc) + ( (num) * (memp_size + memp_align_size(size) ) )
#include "lwip/memp_std.h"
];
假如看不太懂先不同管其中的含義,其實就是lwip在初始化中向記憶體申請空間大小為:mem_alignment - 1+實際需要的記憶體大小。所以這裡就出現為什麼申請要比實際需要的記憶體大小多出mem_alignment - 1個位元組,看一下下面的**:
lwip_mem_align(memp_memory)
原因就是在你申請完這部分空間後,系統會呼叫lwip_mem_align(資料起始位址對齊),而這個操作之前跟大家說過了,會將起始位址向上取整,那麼就會有可能將所申請的空間大小減小[0,mem_alignment - 1],所以在實際申請的記憶體大小中新增mem_alignment - 1來保證對齊後得到的空間大小不小於實際的所需的空間大小。
其中,lwip也有定義相應的巨集定義,來申請所需要的記憶體大小(可以保證對齊後依舊能滿足大小需求)
#define lwip_mem_align_buffer(size) (((size) + mem_alignment - 1))
小議位元組對齊
什麼是位元組對齊,為什麼要對齊 現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。作用和原因 ...
lwip的記憶體管理
至於lwip核心建立多少種pool依賴於使用者和系統配置,比如如果定義了巨集lwip udp為1,那麼在編譯時與udp控制塊資料結構相關的記憶體池pool就會被建立 memp udp pcb 如果定義了巨集lwip tcp為1,編譯時與tcp資料結構相關的記憶體池就會被建立 memp tcp pcb...
記憶體對齊 記憶體對齊規則解釋 記憶體對齊原理
一 記憶體對齊的原因 我們都知道計算機是以位元組 byte 為單位劃分的,理論上來說cpu是可以訪問任一編號的位元組資料的,我們又知道cpu的定址其實是通過位址匯流排來訪問記憶體的,cpu又分為32位和64位,在32位的cpu一次可以處理4個位元組 byte 的資料,那麼cpu實際定址的步長就是4個...