zoukankan      html  css  js  c++  java
  • linux内核内存分配(一、基本概念)

    内存分配是Linux比较复杂也是比较重要的部分,这个和ssd驱动很类似:物理地址和虚拟地址的映射关系。下面总结下最近看到的有关内存分配的内容和自己的理解;

    1、一致内存访问和非一致内存访问


    上图来自《深入linux设备驱动程序内核机制》

    简单的说明下,UMA(一致内存访问 uniform memory access)可以很好的看到所有cpu访问内存的距离都是一样的(其实就是通过总线到内存的速度和距离都是一样的)所以就叫一致内存访问;

    很显然右边的NUMA就是非一致内存访问,内存节点0是CPU0的本地内存(虽然其他CPU也可以访问,但是没有CPU0的速度高),所以这样各个CPU访问内存节点都会首先选择本地内存节点,然后再考虑其他内存节点;

    2、物理内存和虚拟地址

    上图来自《深入linux设备驱动程序内核机制》

    首先大概的可以看出左边的mem_map数组中存放的是page结构体元素,中间的是实际的物理内存,右边的是虚拟的地址范围;

    他们之间的关系大概是这样的,mem_map数组中的元素和物理内存页联系,page指针指向中间的物理内存中的某个物理页,这个关系是为了系统方便管理内存;

    而物理内存页和右边的虚拟地址范围映射,这个是为了操作物理内存,一般右边的虚拟地址由cpu使用(软件上使用的也是虚拟地址,不过该地址最终还是CPU使用)。CPU和MMU之间使用的都是虚拟地址,出了MMU后就转换为实际的物理内存地址,一般有两个地方使用:1、总线上;2、物理内存(可以理解为内存条上);

    这里类比下SSD驱动的原理:FTL数组中存放的是pba(lun、block、page、offset),而数组下标为lba,pba是SSD上的实际物理地址,lba则是上层软件使用的逻辑地址;他们通过FTL数组来映射,这样就可以通过修改数组中的pba来实现SSD像硬盘那样覆盖写等硬盘的特有性能;

    回到内存分配上,从上面的图中应该可以看出物理内存分为三大区域:ZONE_DMA、ZONE_NORMAL、ZONE_HIGHMEM;mem_map数组和物理内存页全部一一映射,也会形成三大区域;而在系统初始化期间,会把物理内存区域中ZONE_DMA和ZONE_NORMAL分别和右边的虚拟地址“物理页面直接映射区”(这个虚拟地址区域名称有点怪,其实就是内核地址的0~896M地址范围)建立线性映射,这样就会建立相应的页目录和页表;如果对右边这个虚拟地址范围分配有疑问的可以看看:http://blog.csdn.net/yuzhihui_no1/article/details/46982231,不过这些都是在32位的系统中的,在64位系统中可以说完全不一样,不过有这个概念会好点;

    这时候,如果在内核内存ZONE_DMA和ZONE_NORMAL区域分配,则可以直接返回虚拟地址(0~896M)这个虚拟地址的界限不是固定的;如果需要在物理内存ZONE_HIGHMEM分配时,则要复杂些了;简单的步骤为:1、在物理内存ZONE_HIGHMEM中查找一个空闲页;2、在右边的虚拟地址中的动态映射区或固定映射区分配一个虚拟地址;3、建立页目录和页表,使物理页和虚拟地址映射起来;

    3、物理页分配接口函数

        首先是:alloc_pages(gfp_mask, order)宏,(是不是很奇怪没有先写kmalloc、vmalloc,那是因为他们俩比较复杂,也比较重要,当然最主要的是他们不是分配物理页。后面要用很大的篇幅来分析他们俩);参数 gfp_mask是一个掩码参数,用来控制分配行为(哪个区域分配、是否阻塞分配等);order是表示分配2的order次方个物理页面;
        alloc_pages(gfp_mask, order); 调用  alloc_pages_node(); 调用 __alloc_pages();说到底最后工作的还是__alloc_pages(),alloc_pages()和__alloc_pages()都可以分配来自ZONE_HIGHMEM区域的物理页,主要看gfp_mask指定的分配区域;  注意alloc_pages()是宏不是函数;
        __get_free_pages(gfp_mask, order);这个分配函数首先是判断gfp_mask,如果指定为ZONE_HIGHMEM分配区域,则失败退出;否则,就调用alloc_pages()函数;由此看出__get_free_pages()函数只能分配ZONE_DMA和ZONE_NORMAL区域的物理页,也就是说不需要修改页表;
    

    简单的分配物理页接口函数就这两个,其他的都是些变种,根据gfp_mask,和order来实现的变种函数;

    注意:这是分配多个的连续的物理页的函数接口,kmalloc、vmalloc函数分配的不一定是整个页大小的内存;

    转载地址:http://blog.csdn.net/yuzhihui_no1/article/details/47284329

    如果讲解的不正确,欢迎指正,谢谢!!

  • 相关阅读:
    Java的Socket通信----通过 Socket 实现 TCP 编程之多线程demo(2)
    MySQL 数据备份与还原
    java实现时钟方法汇总
    java实现二叉树demo
    java实现心型、99乘法demo
    显示本月日历demo
    打开图片并显示在面板上demo
    ArraySort--冒泡排序、选择排序、插入排序工具类demo
    类的实例化顺序
    StringsUtil字符串工具类---灵活截取
  • 原文地址:https://www.cnblogs.com/muahao/p/7460503.html
Copyright © 2011-2022 走看看