Linux 内存管理

来源:互联网 发布:热血仙境数据库修改 编辑:程序博客网 时间:2024/05/22 19:55

 

    在32机器,一个进程可访问的地址范围为0-4G,其中0-3G为用户地址空间,3-4G为内核地址空间;

    不同的进程拥有自己独立的用户空间(TASK_SIZE),共享同一个内核地址空间。

     

    在用户空间只能访问3G(对应物理地址范围是1G-4G),内核地址空间可以访问所有的物理内存。

     

    在内核地址空间的前3G-3G+896M,与物理地址0-896M为直接线性映射关系,那么内核是如果做到可以访问所有的地址空间呢?

     

    1:首先Linux把物理地址划分为三个区域(ZONE_DMA、ZONE_NORMAL、ZONE_HIGHMEM)

            ZONE_DMA:0-16M

            ZONE_NORMAL:16-896M

            ZONE_HIGHMEM:896-4G

    2:内核地址空间(3G-3G+896M)与物理地址0-896M完成一一映射;

    3:剩下的ZONE_HIGHMEM无法直接映射到内核地址空间,因此这一区间的page对应的virtual为NULL;

    4:内核又将内核地址空间的后128M(3G+896M -  4G)分为以下几个部分

     

     

          1):当使用vmalloc时(如ko文件的地址范围),内核先从ZONE_HIGHMEM分配对应的物理地址,然后再从VMALLOC_START -  VMALLOC_END区间分配虚拟地址空间,并建立映射关系;

          2):内核通过alloc_page从ZONE_HIGHMEM分配物理页(注意:在ZONE_HIGHMEM里分配物理页,不能通过_get_free_page,因为_get_free_page返回的是page页对应的所在的逻辑地址(virtual),而ZONE_HIGHMEM里物理页的virtual为NULL,因此只能用alloc_page,alloc_page只会返回page页结构体地址),然后再通过kmap将物理页与PKMAP_BASE- FIXADDR_START的虚拟地址建立映射关系;

     

     

    用户态又是如何使用ZONE_HIGHMEM的内存呢?

    因为用户态可访问的虚拟地址空间(0-3G)对应于物理地址的3G - 4G,该物理地址落在ZONE_HIGHMEM范围内,下面描述用户态使用ZONE_HIGHMEM的过程:

    1:用户态代码通过mmap在虚拟地址空间范围内分配可用的地址空间(vma),并返回分配好的虚拟地址;

    2:用户态代码访问该虚拟地址,由于该虚拟地址还没有与物理地址建立映射关系,产生缺页异常;

    3:以匿名映射为里,内核在缺页处理流程里,最终会通过handle_pte_fault调用do_anonymous_page

    4:在do_anonymous_page里通过alloc_zeroed_user_highpage_movable从ZONE_HIGHMEM分配物理页;

    5:通过page_add_new_anon_rmap(page, vma, vmf->address, false)将分配好的物理页与产生缺页的vma虚拟地址建立映射,然后将物理页填充到pte里(set_pte_at)