【存储管理】brk()系统调用

来源:互联网 发布:nba林书豪成名战数据 编辑:程序博客网 时间:2024/06/10 15:32

尽管应用程序编程时很少直接调用brk()系统调用,但是它是最经常使用的系统调用;


(1)C语言中的malloc以及C++语言中的new都在间接的调用着brk()这个系统调用;内核中含有3GB的用户虚存空间,会部分映射到物理存储空间;用户程序经过编译,链接形成的映像文件中含有一个代码段(在下)和一个数据段(在上,分为data段和bss段),包含所有的静态空间(包含全局变量和static的局部变量)是一个进程所基本必须的,所以在一个进程运行时就必须分配好这些空间,包括虚拟空间和物理页面及其映射;堆栈空间在虚存空间的顶部,运行时向下生长,代码段和数据段在底部,运行时不向上伸展;故数据段的顶部end_data和堆栈空间的下沿是个巨大的空洞,这就是运行时动态分配的空间;最初这个动态分配空间时从进程的end_data开始的,每次动态分配一块内存,这个边界就往上推进一段距离;内核中管理这个边界记录到该进程的mm_struct的 brk成分;当新请求的大小与这个成分相加后,我们又得到了新的成分;一旦新的成分边界要逼近到堆栈空间下沿时,就决绝分配返回-1;


(2)brk()在内核中的实现是sys_brk(),传入的参数是新边界brk,oldbrk可以从mm_struct的 brk成分中获取,若brk小于oldbrk时,为释放内存要该段内存,即调用do_munmap();否则就要分配空间;


do_munmap()解除空间

(1)首先通过find_vma_prev()扫描vm_area_struct或AVL树,试图找到高于adr的第一个地址,返回其前驱的指针,为0时说明原来没有映射;如果这部分空间在某个区间的中间爱你,解除映射后就会留下空洞,是原来的空间一分为二,在不超过虚拟空间的数量情况下;

(2)首先将所有要解除映射的区间转移到一个临时队列free中,解除avl树中的映射,以及将mmap_cache清零;通过while循环中,判断是否是mmap()映射的空间,是就要采用写互斥,使它们从inode的i_mapping队列中移走;zap_page_range()解除若干连续页面的映射,并且释放所映射内存页面或交换设备对物理页面的引用,首先通过pgd_offest()在第一层页面目录中找到起始地址所属的目录项,然后在do-while()中从处理所有的目录项,对每一个目录项,通过zap_pmd_range()处理第二层的中间目录项(二级映射中直接返回指向第一层目录项的指针),然后继续调用zap_page_range(),首先调用pte_get_and_clear()将页面表项清成0,调用free_pte()解除对内存页面以及盘上页面的使用,通过free_page_and_swap_cache()调用delete_from_swap_cache_nolock()将page从LRU队列,换入换出的置换队列,杂凑队列中移走出来,其实也是通过swap_free()释放盘上页面;通过unmap()来完成对vm_area_struct以及mm_struct上的信息更新;对于页面表所占的页面使用free_pgtables()来释放;


在分配空间

(1)首先对进程的资源限制进行判别,看是否超过,此外还要通过find_vma_intersetcion()检查所要求的那部分空间是否与已存在的某一区间相冲突;通过vm_enough_memory()看看系统中是否有足够的空闲内存页面;通过这些条件后,就到了操作的主体do_brk();

(2)在do_brk()中,对于冲突的问题,高端的与堆栈段冲突是不能接受的,而低端与数据段的冲突,进程对可能的错误负责,可解除原来的映射,而对于堆栈段就不能解除原来的映射;合并或新建立一个虚拟空间,最后通过 make_pages_present()产生一次缺页异常,通过handle_mm_fault()来处理;

0 0
原创粉丝点击