您當前的位置:首頁 > 收藏

Linux核心:虛擬地址到物理地址,是什麼時候開始對映

作者:由 玩轉Linux核心 發表于 收藏時間:2021-12-06

核心空間 和使用者空間申請的記憶體最終和buddy怎麼互動?以及在頁表對映上的區別?虛擬地址到物理地址,什麼時候開始對映?

Buddy的問題

分配的力度太大 buddy演算法把空閒頁面分成1,2,4頁,buddy演算法會明確知道哪一頁記憶體空閒還是被佔用?

4k,8k,16k

無論是在應用還是核心,都需要申請很小的記憶體。

從buddy要到的記憶體,會進行slab切割。

slab原理:

比如在核心中申請8位元組的記憶體,buddy分配4K,分成很多個小的8個位元組,每個都是一個object。

slab,slub,slob 是slab機制的三種不同實現演算法。

Linux 會針對一些常規的小的記憶體申請,資料結構,會做slab申請。

cat /proc/slabinfo 可以看到核心空間小塊記憶體的申請情況,也是slab分配的情況。

:每個slab一共可以分出多少個obj, :還可以分配多少個obj, < pagesperslab>:每個slab對應多少個pages, < objperslab>:每個slab可以分出多少個object, < objsize>:每個obj多大,

slab主要分為兩類:

一、常用資料結構像 nfsd_drc, UDPv6,TCPv6 ,這些經常申請和釋放的資料結構。比如,存在TCPv6的slab,之後申請 TCPv6 資料結構時,會透過這個slab來申請。

Linux核心:虛擬地址到物理地址,是什麼時候開始對映

二、常規的小記憶體申請,做的slab。例如 kmalloc-32,kmalloc-64, kmalloc-96, kmalloc-128

Linux核心:虛擬地址到物理地址,是什麼時候開始對映

Linux核心:虛擬地址到物理地址,是什麼時候開始對映

注意,slab申請和分配的都是隻針對核心空間,與使用者空間申請分配記憶體無關。使用者空間的malloc和free呼叫的是libc。

slab和buddy的關係?

1、slab的記憶體來自於buddy。slab相當於二級管理器。

2、slab和buddy在演算法上,級別是對等的。

兩者都是記憶體分配器,buddy是把記憶體條分成多個Zone來管理分配,slab是把從buddy拿到的記憶體,進行管理分配。

同理,malloc 和free也不找buddy拿記憶體。 malloc 和free不是系統呼叫,只是c庫中的函式。

mallopt

在C庫中有一個api是mallopt,可以控制一系列的選項。

Linux核心:虛擬地址到物理地址,是什麼時候開始對映

M_TRIM_THRESHOLD:控制c庫把記憶體還給核心的閾值。

-1UL 代表最大的正整數。

此處代表應用程式把記憶體還給c庫後,c庫並不把記憶體還給核心。

<\do your RT-thing>

程式在此處申請記憶體,都不需要再和核心互動了,此時程式的實時性比較高。

kmalloc vs。 vmalloc/ioremap

記憶體空間: 記憶體+暫存器

register ——> LDR/STR

所有記憶體空間的東西,CPU去訪問,都要透過虛擬地址。 CPU ——> virt ——> mmu ——> phys

cpu請求虛擬地址,mmu根據cpu請求的虛擬地址,查頁表的物理地址。

buddy演算法,管理這一頁的使用情況。

兩個虛擬地址可以對映到同一個物理地址。

Linux核心:虛擬地址到物理地址,是什麼時候開始對映

頁表 -> 陣列,

任何一個虛擬地址,都可以用地址的高20位,作為頁表的行號去讀對應的頁表項。而第12位,是指頁面內偏移。(由於一頁是4K,2^12 足夠描述)

kmalloc 和 vmalloc 申請的記憶體,有什麼區別? 答:申請之後,是否還要去改頁表。一般情況,kmalloc申請記憶體,不需要再去改頁表。同一張頁表,幾個虛擬地址可以同時對映到同一個物理地址。

暫存器,透過ioremap往vmalloc區域,進行對映。然後改程序的虛擬地址頁表。

總結:所有的頁,最底層都是用buddy演算法進行管理,用虛擬地址找物理地址。理解記憶體分配和對映的區別,無論是lowmem還是highmem 都可以被vmalloc拿走,也可能被使用者拿走,只不過拿走之後,還要把虛擬地址往物理地址再對映一遍。但如果是被kmalloc拿走,一般指低端記憶體,就不需要再改程序的頁表。因為這部分低端記憶體,已經做好了虛實對映。

cat /proc/vmallocinfo |grep ioremap

可以看到暫存器中的哪個區域,被對映到哪個虛擬地址。

vmalloc區域主要用來,vmalloc申請的記憶體從這裡找虛擬地址 和 暫存器的ioremap對映。

Linux記憶體分配的lazy行為

Linux總是以最lazy的方式,給應用程式分配記憶體。

Linux核心:虛擬地址到物理地址,是什麼時候開始對映

malloc100M記憶體成功時,其實並沒有真實拿到。只有當100M記憶體中的任何一頁,被寫一次的時候,才成功。vss:虛擬地址空間。 rss:常駐記憶體空間malloc 100M記憶體成功時,Linux把100M記憶體全部以只讀的形式,對映到一個全部清0的頁面。

當應用程式寫100M中每一頁任意位元組時,會發出page fault。 linux 核心收到缺頁中斷後,從硬體暫存器中讀取到,包括缺頁中斷髮生的原因和虛擬地址。Linux從記憶體條申請一頁記憶體,執行cow,把頁面重新複製到新申請的頁表,再把程序頁表中的虛擬地址,指向一個新的物理地址,許可權也被改成R+W。

呼叫brk 把8k變成 16k。

針對應用程式的堆、程式碼、棧、等,會使用lazy分配機制,只有當寫記憶體頁時,才會真實請求記憶體分配頁表。但,當核心使用kmalloc申請記憶體時,就真實地分配相應的記憶體,不使用lazy機制。

記憶體OOM

當真實去寫記憶體時,應用程式並不能拿到真實的記憶體時。Linux啟動OOM,linux在執行時,會對每一個程序進行out-of-memory打分。大部分主要基於,耗費的記憶體。耗費的記憶體越多,打分越高。

cat /proc//oom_score

#include

#include

#include

int main(int argc, char **argv)

{

int max = -1;

int mb = 0;

char *buffer;

int i;

#define SIZE 2000

unsigned int *p = malloc(1024 * 1024 * SIZE);

printf(“malloc buffer: %p\n”, p);

for (i = 0; i < 1024 * 1024 * (SIZE/sizeof(int)); i++) {

p[i] = 123;

if ((i & 0xFFFFF) == 0) {

printf(“%dMB written\n”, i >> 18);

usleep(100000);

}

}

pause();

return 0;

}

定條件:

總記憶體1G

1、swapoff -a 關掉swap交換

2、echo 1 >

/proc/sys/vm/overcommit_memory

3、核心不去評估系統還有多少空閒記憶體

Linux進行OOM打分,主要是看耗費記憶體情況,此外還會參考使用者許可權,比如root許可權,打分會減少30分。

還有OOM打分因子:/proc/pid/oom_score_adj (加減)和 /proc/pid/oom_adj (乘除)。

總結:

1、slab的作用,針對在核心空間小記憶體分配,和常用資料結構的申請。

2、同樣的二次分配器,在使用者空間是C庫。malloc和free的時候,記憶體不一定從buddy分配和還給buddy。

3、kmalloc,vmalloc 和malloc的區別

kmalloc:申請記憶體,一般在低端記憶體區。申請到時,記憶體已經對映過了,不需要再去改程序的頁表。所以,申請到的物理頁是連續的。

vmalloc:申請記憶體,申請到就拿到記憶體,並且已經修改了程序頁表的虛擬地址到物理地址的對映。vmalloc()申請的記憶體並不保證物理地址的連續。

使用者空間的malloc:申請記憶體,申請到並沒有拿到,寫的時候才去拿到。拿到之後,才去改頁表。申請成功,頁表只讀,只有到寫時,發生page fault,才去buddy拿記憶體。

kmalloc和vmalloc針對核心空間,malloc針對使用者空間。這些記憶體,可以來自任何一個Zone。

無論是kmalloc,vmalloc還是使用者空間的malloc,都可以使用記憶體條的不同Zone,無論是highmem zone、lowmem zone 和 DMA zone。

4、如果在從buddy拿不到記憶體時,會觸發Linux對所有程序進行OOM打分。當Linux出現記憶體耗盡,就kill一個oom score 最高的是那個程序。oom_score,可以根據 oom_adj (-17~25)。

安卓的程式,不停地調整前臺和後臺程序oom_score,當被切換到後臺時,oom_score會被調整得比較大。以保證前臺的程序不容易因為oom而kill掉。

Linux核心:虛擬地址到物理地址,是什麼時候開始對映

標簽: 記憶體  slab  Buddy  頁表  虛擬地址