原文:https://blog.csdn.net/jy1075518049/article/details/43610569
兩種內存管理方式:
1、內存尋址--段式管理
三個名詞:邏輯地址、線性地址、物理地址
物理地址:最容易理解的,它就是實實在在物理內存上的地址,你PC上有1G內存,那最大地址就是0x40000000,0x800就是代表1KB的地址。
線性地址:這是APP用的地址,也就是我們程序員寫代碼用的地址,它是一個虛擬地址,最終會被轉化到物理地址。
邏輯地址:這是最麻煩的一個地址了,它是針對x86的架構形成的地址,先不用理會。
問題背景:早起x86的CPU內部有20根地址線,能尋址2^20個地址,也就是1MB。但是寄存器只有16位,只能尋址2^16個地址,也就是64KB。怎么利用寄存器的16位來尋址1MB呢?
解決方案:intel想一個辦法,尋址分為兩部分:基地址和偏移地址。首先CPU要到CS(代碼段寄存器)中取出基地址,然后再到IP寄存器中取出指令偏移量,組合成一個20位地址(這就是線性地址)然后尋址。但是還是不夠,寄存器都是16位的,那么相加能表示的最大地址就是 0xffff+0xffff=128KB。為了解決這個問題,cs寄存器中的數字不再代表實際基地址,而是基地址的索引。1MB的內存分成29個64KB,cs寄存器中存放1-29這30個數字,線性地址 = cs*64KB + IP。
邏輯地址再說明一下:

邏輯地址的選擇符就對應上面講的CS寄存器,偏移量對應IP寄存器。32位操作系統嫌32的寄存器能表達的信息太少,不用上面講的直接得出線性地址。而是再做一次轉換,先把段基址存到一塊內存,每個段基址占8字節(64位),當然這8字節里面還含有其他描述信息,描述符會把index字段*8得到某個段的描述符的地址,然后跑到那個地址取出里邊的段基址再加上IP寄存器的偏移量就得到線性地址了。
總結:段式管理可以解決短位寄存器訪問大內存的問題。但是如果這樣20位的CPU系統只能支持最大的內存為64KB,這樣當然不可取。下面再介紹分頁管理機制。
2、頁式管理機制(linux下內核開發管理內存的方式)
頁目錄、頁表:頁式管理的兩個線性表,用來查找存線性地址的頁
頁框:對應真正的物理地址,以4KB為邊界。
一個32位的線性地址會被分成3個部分,10位頁目錄,10位頁表,12位頁偏移。理解為內存中存儲的一張張的擁有1024個表項的二維表,頁目錄每一項存放的是某個頁表的地址,而頁表中每一項存放的是某個頁的地址。可以想象為C語言中指針。
舉個例子:
線性地址是 0x00401001 ,表示為二進制是 0000000001 0000000001 000000000001 ,對應上面三個名詞,那么頁目錄值、頁表值和頁內偏移值都是1,也就說要想找到真正的物理地址,首先應該到頁目錄(擁有1024個頁目錄項)的第一項中尋址,這個項中存的是頁表的地址,假如是1000,CPU就會跑到1000的物理地址(注意,真的是物理地址)上找到某個頁表,這個頁表又擁有1024項的頁表項。然后拿到第二個10位地址(還是1),也就說到第一個頁表上的第一項,到這里,其實就已經能找到物理內存塊了。想一下,每個頁表項代表4KB,每個頁表又1024個頁表項,而頁目錄項總共有1024個頁目錄項(=1024張頁表),所以能表示的總大小正好是4kb*1024*1024=4GB。要定位到具體的字節就用到最后的12位了,再加上12位的偏移值即可。
3、DPDK 使用大頁
上面介紹的頁式管理機制,引入TLB概念(轉換后備緩沖器 translation lookaside buffer),TLB中保存着邏輯地址前20位(頁目錄、頁表)和頁號(物理地址)的對應關系,如果匹配到邏輯地址就可以迅速的找到頁號,通過頁號與邏輯地址的后12位的偏移組合得到最終的物理地址。
所以,如果一個程序使用了2MB的內存,那么需要512個頁表表項(512*4KB=2048KB=2MB)才能保證不會出現TLB不命中的情況。由於TLB資源是有限的,隨着內存使用的增加,勢必增加TLB不命中的情況。自然會想到,如果頁框的值為2M,只需要一個TLB。由於DPDK性能的要求和內存的大量使用,自然引入大頁的概念。
Linux操作系統采用了基於hugetlbfs 的2MB或者1GB的大頁面的支持。修改內核參數即可預留大頁。
非NUMA系統中,預留1024個大小為2M的大頁
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kb/nr_hugepages
NUMA系統中,兩個NODE的系統中,預留1024個2M的大頁
echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kb/nr_hugepages
echo 1024 > /sys/devices/system/node/node1/hugepages/hugepages-2048kb/nr_hugepages
大頁預留了,下面講到使用的問題。DPDK使用HUGETLBFS來使用大頁。首先,它需要把大頁mount到某個路徑 比如 /mnt/huge。
mkdir /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
可以開機時自動掛載:
nodev /mnt/huge hugetlbfs defaults 0 0
接下來,DPDK運行的時候,會使用mmap()系統調用把大頁映射到用戶態的虛擬地址空間(在堆和棧之間),然后就可以正常使用了。
ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0);第一個參數為映射的起始地址,填NULL表示由內核分配起始地址。如果填寫指定的地址,該指定的地址需要在LD鏈接的時候預留好。LD詳細信息為 ld -verbose
4、DPDK內存管理分析
