一、内核内存布局
-
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文章
19242浏览量
229593 -
内核
+关注
关注
3文章
1372浏览量
40272 -
Linux
+关注
关注
87文章
11279浏览量
209264 -
AIoT
+关注
关注
8文章
1405浏览量
30631
原文标题:接上一篇续集
文章出处:【微信号:嵌入式开发AIoT,微信公众号:嵌入式开发AIoT】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论