brk() 和 mmap() 内存映射

参考博文:http://www.cnblogs.com/huxiao-tee/p/4660352.html

  • x86平台下linux进程虚拟地址空间分布(2.6.7以前版本)

    mmap区域与栈区域相对增长,只有1GB连续的虚拟地址空间可用。

  • x86平台下linux进程虚拟地址空间分布(2.6.7以后版本)

Random stack offset:由于之前栈的地址是固定的,容易被人利用栈溢出进行攻击,这里栈每次有一个偏移量。

RLIMIT_STACK:向栈中压入数据容量超过栈的容量时,会触发page fault,异常会检测到最近的虚拟地址空间,发现产生异常的地址与栈相邻,会扩大栈的大小(一般是8M)。如果栈被加长,栈针回退时不会再收缩,如果stack overflow则会导致segment fault。

Memory Mapping Segment:内存映射的位置,一种高效I/O,后面会细说。

  • 对heap的操作函数  brk() 和 sbrk()  

      int brk(void *addr);

    void sbrk(intptr_t increment);

    内核数据结构mm_struct中 start_brk是进程动态分配的起始地址(heap的起始地址),brk 是堆当前最后的地址。      

    首先program break就是当前brk的位置,所以他是数据段初始化结束后heap的第一个位置,而不是heap的尾部。

    sbrk()是库函数,brk()是系统调用,相对于库函数来说一般系统调用会提供相对简单的工作。都是改变brk的值来扩展收缩堆(increment 为负数时收缩)。

  • mmap 映射区函数

   1.基础概念

    mmap 是一种内存映射方法,将一个文件或其他对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址一一对应的关系。内核空间对这块区域的改变也直接反应到用户空间,实现不同进程的文件共享。

    linux内核使用vm_area_struct结构表示一个独立的虚拟内存区域,一个进程使用多个vm_area_struct来分别表示不同类型的虚拟内存区域.

    当vm_area_struct数目较少时,按照升序以单恋表的形式组织结构,在数目较多时使用AVL树来实现。

v

mmap函数是创建一个新的vm_area_struct结构,并将其与物理地址相连

   2.  mmap内存映射原理

    分为三个阶段

    • 进程启动映射过程,并在虚拟地址空间中为映射创建虚拟映射区域  

       1>进程在用户空间调用mmap。

       原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

       2>在当前进程的虚拟地址空间中,寻找一段空间满足要求的连续的虚拟地址。

       3>为此虚拟区分配一个vm_area_struct 结构,接着对这个结构的各个域进行初始化

       4>将新建的虚拟结构(vm_area_struct)插入到进程的虚拟地址区的链表或数种。

    • 调用内核空间的系统调用函数mmap(不同于用户空间)实现文件物理地址和进程虚拟地址的一一映射关系 

       5>为映射分配了新的虚拟地址区域后,通过待映射的文件指针,在文件描述符表中找到对应的文件描述符,加入到struct file中 

       6>linux中的file_operation结构中定义了不同事件对应的设备驱动函数,其中有  int mmap(struct file *filp, struct vm_area_struct *vma),其实这个函数就是将用户空间与设备内存相连,也就是对虚拟地址的访问转化为对设备的访问

       7>通过inode模块找到对应的文件,也就是磁盘的物理地址

       8>建立页表,实现文件地址和虚拟地址区域的映射关系。这里只建立了映射关系,主存中没有对应物理地址的数据。

    • 进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到主存的拷贝

       9>进程的读写,通过查询页表发现这一段地址不再物理页面上,引发缺页异常

       10>进行缺页异常判断,申请调页

       11>先判断swap cache中没有没需要访问的内存页,如果没有调用nopage把所缺德页从磁盘装入主存

       12>之后可以进行读写,会有一段时间延迟,调用msync()立即更新。

   3. mmap优点总结

         1>对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,使用内存读取代了I/O操作,提高了文件读取效率。

    2>实现了用户空间和内核空间的高效交互方式

    3>提供进程间共享内存及相互通信方式

    4>实现高效的大规模数据传输

 

还有内核的高端内存映射:https://www.cnblogs.com/wuchanming/p/4360277.html

 

posted @ 2018-02-08 14:34  张铁子  阅读(2907)  评论(0编辑  收藏  举报