一、內核內存布局
-
ARM64架構處理器采用48位物理尋址機制,最大可尋找256TB的物理地址空間。對于 目前應用完全足夠,不需要擴展到64位的物理尋址。虛擬地址也同樣最大支持48位尋址,所以 在處理器架構設計上,把虛擬地址空間劃分為兩個空間,每個空間最大支持256TB,linux內核 在大多數體系結構上都把兩個地址劃分為:用戶空間和內核空間。
-
用戶空間:0x0000_0000_0000_0000至0x0000_ffff_ffff_ffff;
-
內核空間:0xffff_0000_0000_0000至0xffff_ffff_ffff_ffff;
QEMU平臺,可以打印ARM64架構linux內核內存分布情況
二、堆管理
堆是進程中主要用于動態分配變量和數據的內存區域,堆的管理對應程序員不是直接可見的。因為它依賴標準庫提供的各個輔助函數(其中最重要的是malloc)來分配任意長度的內存區。malloc和內核之間的經典接口是brk系統調用,負責擴展/收縮堆。
- 堆是一個連續的內存區域,在擴展時自下至上增長。其中mm_struct結構,包含堆在虛擬地 址空間中的起始和當前結束地址(start_brk和brk)。
- brk系統調用用于指定堆在虛擬地址空間中新的結束地址(如果堆將要收縮,當然可以小于當前值)。brk系統調用通過do_brk增長動態分配區(內核源碼分mm/mmap.c)
三、sys_brk流程
-
檢查資源限制;
-
將brk值對齊到頁;
-
是否想增加brk值?(這個地方要結合源碼看)
是-->
do_brk()
;返回新的brk的值;否-->
do_munmap()
;返回新的brk的值;
brk機制不是一個獨立的內核概念,而是基于匿名映射實現,以減少內部的開銷。在檢查過用brk的值的新地址未超出推的限制之后,
sys_brk
第一個重要操作是請求的地址按頁長對齊。brk()
用于進程向內核申請空間,用于擴展用戶堆棧空間,或者回收堆棧空間。
-
malloc為小空間申請,
brk()
為大塊空間申請。do_brk()
用于增長動態分配區。do_munmap()
釋放動態分配區; -
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這個長度進行頁面對齊去判斷頁面對齊之后是否超出邊界
len=PAGE_ALIGN(len);
if(!len)
returnaddr;
flags=VM_DATA_DEFAULT_FLAGS|VM_ACCOUNT|mm->def_flags;
//檢查是否有足夠內存空間來分析len大小的內存。判斷虛擬地址空間是否足夠
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
*/
//循環遍歷用戶進程紅黑樹中VMA,然后根據addr來查找合適的插入點
while(find_vma_links(mm,addr,addr+len,&prev,&rb_link,
&rb_parent)){
if(do_munmap(mm,addr,len))
return-ENOMEM;
}
/*Checkagainstaddressspacelimits*after*clearingoldmaps...*/
//檢查是否要對此虛擬區間進行擴充
if(!may_expand_vm(mm,len>>PAGE_SHIFT))
return-ENOMEM;
if(mm->map_count>sysctl_max_map_count)
return-ENOMEM;
//判斷系統是否有足夠內存
if(security_vm_enough_memory_mm(mm,len>>PAGE_SHIFT))
return-ENOMEM;
/*Canwejustexpandanoldprivateanonymousmapping?*/
//判讀是否可以合并,如果可以合并就合并成為一個vam區
vma=vma_merge(mm,prev,addr,addr+len,flags,
NULL,NULL,pgoff,NULL,NULL_VM_UFFD_CTX);
//如果能合并直接gotoout
if(vma)
gotoout;
/*
*createavmastructforananonymousmapping
*/
//如果沒有辦法合并,只有新創建一個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所屬于進程structmm_struct結構
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://增加進程地址空間長度
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 -
審核編輯 :李倩
-
處理器
+關注
關注
68文章
19178瀏覽量
229201 -
內核
+關注
關注
3文章
1366瀏覽量
40236 -
Linux
+關注
關注
87文章
11232瀏覽量
208958 -
AIoT
+關注
關注
8文章
1392瀏覽量
30578
原文標題:接上一篇續集
文章出處:【微信號:嵌入式開發AIoT,微信公眾號:嵌入式開發AIoT】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論