一、內(nèi)核內(nèi)存布局
-
ARM64架構(gòu)處理器采用48位物理尋址機(jī)制,最大可尋找256TB的物理地址空間。對于 目前應(yīng)用完全足夠,不需要擴(kuò)展到64位的物理尋址。虛擬地址也同樣最大支持48位尋址,所以 在處理器架構(gòu)設(shè)計(jì)上,把虛擬地址空間劃分為兩個空間,每個空間最大支持256TB,linux內(nèi)核 在大多數(shù)體系結(jié)構(gòu)上都把兩個地址劃分為:用戶空間和內(nèi)核空間。
-
用戶空間:0x0000_0000_0000_0000至0x0000_ffff_ffff_ffff;
-
內(nèi)核空間:0xffff_0000_0000_0000至0xffff_ffff_ffff_ffff;
QEMU平臺,可以打印ARM64架構(gòu)linux內(nèi)核內(nèi)存分布情況
二、堆管理
堆是進(jìn)程中主要用于動態(tài)分配變量和數(shù)據(jù)的內(nèi)存區(qū)域,堆的管理對應(yīng)程序員不是直接可見的。因?yàn)樗蕾嚇?biāo)準(zhǔn)庫提供的各個輔助函數(shù)(其中最重要的是malloc)來分配任意長度的內(nèi)存區(qū)。malloc和內(nèi)核之間的經(jīng)典接口是brk系統(tǒng)調(diào)用,負(fù)責(zé)擴(kuò)展/收縮堆。
- 堆是一個連續(xù)的內(nèi)存區(qū)域,在擴(kuò)展時(shí)自下至上增長。其中mm_struct結(jié)構(gòu),包含堆在虛擬地 址空間中的起始和當(dāng)前結(jié)束地址(start_brk和brk)。
- brk系統(tǒng)調(diào)用用于指定堆在虛擬地址空間中新的結(jié)束地址(如果堆將要收縮,當(dāng)然可以小于當(dāng)前值)。brk系統(tǒng)調(diào)用通過do_brk增長動態(tài)分配區(qū)(內(nèi)核源碼分mm/mmap.c)
三、sys_brk流程
-
檢查資源限制;
-
將brk值對齊到頁;
-
是否想增加brk值?(這個地方要結(jié)合源碼看)
是-->
do_brk()
;返回新的brk的值;否-->
do_munmap()
;返回新的brk的值;
brk機(jī)制不是一個獨(dú)立的內(nèi)核概念,而是基于匿名映射實(shí)現(xiàn),以減少內(nèi)部的開銷。在檢查過用brk的值的新地址未超出推的限制之后,
sys_brk
第一個重要操作是請求的地址按頁長對齊。brk()
用于進(jìn)程向內(nèi)核申請空間,用于擴(kuò)展用戶堆??臻g,或者回收堆棧空間。
-
malloc為小空間申請,
brk()
為大塊空間申請。do_brk()
用于增長動態(tài)分配區(qū)。do_munmap()
釋放動態(tài)分配區(qū); -
do_brk()
源碼分析:
staticunsignedlongdo_brk(unsignedlongaddr,unsignedlonglen)
{
structmm_struct*mm=current->mm;
structvm_area_struct*vma,*prev;
unsignedlongflags;
structrb_node**rb_link,*rb_parent;
pgoff_tpgoff=addr>>PAGE_SHIFT;
interror;
//首先對len這個長度進(jìn)行頁面對齊去判斷頁面對齊之后是否超出邊界
len=PAGE_ALIGN(len);
if(!len)
returnaddr;
flags=VM_DATA_DEFAULT_FLAGS|VM_ACCOUNT|mm->def_flags;
//檢查是否有足夠內(nèi)存空間來分析len大小的內(nèi)存。判斷虛擬地址空間是否足夠
error=get_unmapped_area(NULL,addr,len,0,MAP_FIXED);
if(offset_in_page(error))
returnerror;
error=mlock_future_check(mm,mm->def_flags,len);
if(error)
returnerror;
/*
*mm->mmap_semisrequiredtoprotectagainstanotherthread
*changingthemappingsincasewesleep.
*/
verify_mm_writelocked(mm);
/*
*Clearoldmaps.thisalsodoessomeerrorcheckingforus
*/
//循環(huán)遍歷用戶進(jìn)程紅黑樹中VMA,然后根據(jù)addr來查找合適的插入點(diǎn)
while(find_vma_links(mm,addr,addr+len,&prev,&rb_link,
&rb_parent)){
if(do_munmap(mm,addr,len))
return-ENOMEM;
}
/*Checkagainstaddressspacelimits*after*clearingoldmaps...*/
//檢查是否要對此虛擬區(qū)間進(jìn)行擴(kuò)充
if(!may_expand_vm(mm,len>>PAGE_SHIFT))
return-ENOMEM;
if(mm->map_count>sysctl_max_map_count)
return-ENOMEM;
//判斷系統(tǒng)是否有足夠內(nèi)存
if(security_vm_enough_memory_mm(mm,len>>PAGE_SHIFT))
return-ENOMEM;
/*Canwejustexpandanoldprivateanonymousmapping?*/
//判讀是否可以合并,如果可以合并就合并成為一個vam區(qū)
vma=vma_merge(mm,prev,addr,addr+len,flags,
NULL,NULL,pgoff,NULL,NULL_VM_UFFD_CTX);
//如果能合并直接gotoout
if(vma)
gotoout;
/*
*createavmastructforananonymousmapping
*/
//如果沒有辦法合并,只有新創(chuàng)建一個VMA,VMA地址空間是【addr,addr+len】
vma=kmem_cache_zalloc(vm_area_cachep,GFP_KERNEL);
if(!vma){
vm_unacct_memory(len>>PAGE_SHIFT);
return-ENOMEM;
}
//指向匿名域指針
INIT_LIST_HEAD(&vma->anon_vma_chain);
vma->vm_mm=mm;//指向VMA所屬于進(jìn)程structmm_struct結(jié)構(gòu)
vma->vm_start=addr;
vma->vm_end=addr+len;
vma->vm_pgoff=pgoff;
vma->vm_flags=flags;
vma->vm_page_prot=vm_get_page_prot(flags);
vma_link(mm,vma,prev,rb_link,rb_parent);
out://增加進(jìn)程地址空間長度
perf_event_mmap(vma);
mm->total_vm+=len>>PAGE_SHIFT;
if(flags&VM_LOCKED)
mm->locked_vm+=(len>>PAGE_SHIFT);
vma->vm_flags|=VM_SOFTDIRTY;
returnaddr;
}
- END -
審核編輯 :李倩
-
處理器
+關(guān)注
關(guān)注
68文章
19404瀏覽量
230914 -
內(nèi)核
+關(guān)注
關(guān)注
3文章
1382瀏覽量
40385 -
Linux
+關(guān)注
關(guān)注
87文章
11342瀏覽量
210222 -
AIoT
+關(guān)注
關(guān)注
8文章
1418瀏覽量
30887
原文標(biāo)題:接上一篇續(xù)集
文章出處:【微信號:嵌入式開發(fā)AIoT,微信公眾號:嵌入式開發(fā)AIoT】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論