内核空間 和用戶空間申請的内存最終和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分配的情況。
<num_objs>:每個slab一共可以分出多少個obj, <active_objs> :還可以分配多少個obj, < pagesperslab>:每個slab對應多少個pages, < objperslab>:每個slab可以分出多少個object, < objsize>:每個obj多大,
slab主要分為兩類:
一、常用數據結構像 nfsd_drc, UDPv6,TCPv6 ,這些經常申請和釋放的數據結構。比如,存在TCPv6的slab,之後申請 TCPv6 數據結構時,會通過這個slab來申請。
二、常規的小内存申請,做的slab。例如 kmalloc-32,kmalloc-64, kmalloc-96, kmalloc-128
注意,slab申請和分配的都是隻針對内核空間,與用戶空間申請分配内存無關。用戶空間的malloc和free調用的是libc。
更多Linux内核視頻教程文檔資料免費領取後台私信【内核大禮包】自行獲取。
slab和buddy的關系?1、slab的内存來自于buddy。slab相當于二級管理器。2、slab和buddy在算法上,級别是對等的。
兩者都是内存分配器,buddy是把内存條分成多個Zone來管理分配,slab是把從buddy拿到的内存,進行管理分配。
同理,malloc 和free也不找buddy拿内存。 malloc 和free不是系統調用,隻是c庫中的函數。
mallopt在C庫中有一個api是mallopt,可以控制一系列的選項。
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算法,管理這一頁的使用情況。
兩個虛拟地址可以映射到同一個物理地址。
頁表 -> 數組,任何一個虛拟地址,都可以用地址的高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的方式,給應用程序分配内存。
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/<pid>/oom_score
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
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;
}
定條件:
總内存1G1、swapoff -a 關掉swap交換2、echo 1 > /proc/sys/vm/overcommit_memory3、内核不去評估系統還有多少空閑内存
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的區别
4、如果在從buddy拿不到内存時,會觸發Linux對所有進程進行OOM打分。當Linux出現内存耗盡,就kill一個oom score 最高的是那個進程。oom_score,可以根據 oom_adj (-17~25)。
安卓的程序,不停地調整前台和後台進程oom_score,當被切換到後台時,oom_score會被調整得比較大。以保證前台的進程不容易因為oom而kill掉。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!