转自:http://blog.csdn.net/myarrow/article/details/8682819

1. First Fit分配器

First Fit分配器是最基本的内存分配器,它使用bitmap而不是空闲块列表来表示内存。在bitmap中,如果page对应位为1,则表示此page已经被分配,为0则表示此page没有被分配。为了分配小于一个page的内存块,First Fit分配器记录了最后被分配的PFN (Page Frame Number)和分配的结束地址在页内的偏移量。随后小的内存分配被Merge到一起并存储到同一页中。

First Fit分配器不会造成严重的内存碎片,但其效率较低,由于内存经常通过线性地址进行search,而First Fit中的小块内存经常在物理内存的开始处,为了分配大块内存而不得不扫描前面大量的内存。

2. Boot Memory分配器

物理内存分配器如何分配内存来初始化其自己呢?

答案是:通过Boot Memory分配器来实现,而Boot Memory分配器则通过最基本的First Fit分配器来实现。

2.1 Boot Map定义

Boot Map通过数据结构bootmem_data来定义,详见<linux/bootmem.h>,其定义如下所示:

[cpp] view plaincopy
  1. typedef struct bootmem_data {
  2. unsigned long node_boot_start; // 描述的物理内存的起始地址
  3. unsigned long node_low_pfn;    // 结束物理地址,即ZONE_NORMAL的结束
  4. void *node_bootmem_map;        // 描述“使用或空闲的位图”的地址
  5. unsigned long last_offset;     // 最后被分配的页内偏移量,即在llast_pos描述的物理页中,
  6. // 从last_offset开始,没有被分配
  7. unsigned long last_pos;        // 最后被分配的页的PFN
  8. } bootmem_data_t;

所有bootmem_data被放于全局变量bdata_list中。

2.2 Boot Memory分配器初始化

每一个CPU架构被要求提供setup_arch函数,它负责获取初始化boot memory分配器的必要参数。不同的CPU架构通过不同的函数来实现,如ARM通过bootmem_init来实现。它负责获取以下参数:

• min_low_pfn: 系统中可获得的最小的PFN,装载kernel image结束之后的第一页,在mm/bootmem.c中定义

• max_low_pfn:低端内存(ZONE_NORMAL)中可获得的最大PFN

• highstart_pfn:高端内存(ZONE_HIGHMEM)的起始PFN

• highend_pfn:高端内存(ZONE_HIGHMEM)的结束PFN

• max_pfn:系统中可获得的最大的PFN, 在mm/bootmem.c中定义

PFN是在物理内存map的偏移量,以page为单位。Kernel可直接访问ZONE_NORMAL,其偏移量为:PAGE_OFFSET。

通过以上5个参数明确了可用物理内存之后,调用init_bootmem->init_bootmem_core来初始化contig_page_data。它主要完成以下两件事:

1) 将把与此node对应pgdat_data_t插入到pgdat_list中

2) 初始化bootmem_data_t的中参数,并分配表示页分配状态的bitmap,其大小为: (end_pfn-start_pfn+7)/8

bitmap的物理地址为:bootmem_data_t->node_boot_start

bitmap的虚拟地直为:bootmem_data_t->node_bootmem_map

2.3 分配内存

• reserve_bootmem:用于预留物理页面。但用于通用的内存分配是低率的,它主要用于各种驱动(如:Video Codec)预留内存。

常用的内存分配函数如下(in UMA架构,我们常的ARM架构为UMA架构):

• alloc_bootmem

• alloc_bootmem_low

• alloc_bootmem_pages

• alloc_bootmem_low_pages

其调用关系如下图所示:

2.3.1  __alloc_bootmem

__alloc_bootmem() 需要以下参数:

     • pgdat

用于分配内存块的节点,在UMA架构中,它被忽略,因为它总是为:contig_page_data

     • size

指定请求分配的内存大小,以字节为单位

     • align

请求以多少字节对齐,地于小块内存分配,一般以SMP_CACHE_BYTES对齐,如在X86上,与L1硬件cache对齐

     • goal

偏好的分配内存的起始地址,

2.3.2 __alloc_bootmem_core

它从goal指定的地址开始,线性地扫描内存,以寻找可以满足内存分配要求的内存块。它的另外一项功能是决定是否需要把新分配的内存块与以前已经分配的内存块merge到一起。

分配内存常用函数定义如下:

[cpp] view plaincopy
  1. #ifdef CONFIG_NO_BOOTMEM
  2. /* We are using top down, so it is safe to use 0 here */
  3. #define BOOTMEM_LOW_LIMIT 0
  4. #else
  5. #define BOOTMEM_LOW_LIMIT __pa(MAX_DMA_ADDRESS)
  6. #endif
  7. #define alloc_bootmem(x) \
  8. __alloc_bootmem(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
  9. #define alloc_bootmem_align(x, align) \
  10. __alloc_bootmem(x, align, BOOTMEM_LOW_LIMIT)
  11. #define alloc_bootmem_nopanic(x) \
  12. __alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
  13. #define alloc_bootmem_pages(x) \
  14. __alloc_bootmem(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
  15. #define alloc_bootmem_pages_nopanic(x) \
  16. __alloc_bootmem_nopanic(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
  17. #define alloc_bootmem_node(pgdat, x) \
  18. __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
  19. #define alloc_bootmem_node_nopanic(pgdat, x) \
  20. __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
  21. #define alloc_bootmem_pages_node(pgdat, x) \
  22. __alloc_bootmem_node(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
  23. #define alloc_bootmem_pages_node_nopanic(pgdat, x) \
  24. __alloc_bootmem_node_nopanic(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
  25. #define alloc_bootmem_low(x) \
  26. __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0)
  27. #define alloc_bootmem_low_pages(x) \
  28. __alloc_bootmem_low(x, PAGE_SIZE, 0)
  29. #define alloc_bootmem_low_pages_node(pgdat, x) \
  30. __alloc_bootmem_low_node(pgdat, x, PAGE_SIZE, 0)

2.4 释放内存

调用free_bootmem来释放内存。

[cpp] view plaincopy
  1. void __init free_bootmem(unsigned long addr, unsigned long size)
  2. {
  3. unsigned long start, end;
  4. kmemleak_free_part(__va(addr), size);
  5. start = PFN_UP(addr);
  6. end = PFN_DOWN(addr + size);
  7. mark_bootmem(start, end, 0, 0);
  8. }
【作者】张昺华
【出处】http://www.cnblogs.com/sky-heaven/
【博客园】 http://www.cnblogs.com/sky-heaven/
【新浪博客】 http://blog.sina.com.cn/u/2049150530
【知乎】 http://www.zhihu.com/people/zhang-bing-hua
【我的作品---旋转倒立摆】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【我的作品---自平衡自动循迹车】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

Linux内存管理--物理内存分配【转】相关推荐

  1. Linux内存管理 (4)分配物理页面

    专题:Linux内存管理专题 关键词:分配掩码.伙伴系统.水位(watermark).空闲伙伴块合并. 我们知道Linux内存管理是以页为单位进行的,对内存的管理是通过伙伴系统进行. 从Linux内存 ...

  2. Linux内存管理(六): 分配物理内存alloc_pages

    基于Linux 5.10, 体系结构是aarch64 上文介绍了linux对物理内存的描述,本篇介绍linux下物理页面的分配函数alloc_pages 1.API接口 alloc_pages是内核中 ...

  3. Linux 内存管理 | 物理内存管理:物理内存、内存碎片、伙伴系统、slab分配器

    文章目录 物理内存 物理内存分配 内存碎片 外部碎片 内部碎片 伙伴系统(buddy system) slab分配器 本文举例为32位Linux 物理内存 在Linux中,内核将物理内存划分为三个区域 ...

  4. Linux 内存管理 | 物理内存、内存碎片、伙伴系统、SLAB分配器

    文章目录 物理内存 物理内存分配 外部碎片 内部碎片 伙伴系统(buddy system) slab分配器 物理内存 在Linux中,内核将物理内存划分为三个区域. 在解释DMA内存区域之前解释一下什 ...

  5. Linux内存管理: 物理内存的释放(回收).为物理页面抬棺

    前情提要: 地址转换 物理页面的分配 终于到了物理内存的释放. 内存页面如生命一般. 有生有死. 接下来我们就要为物理页面抬棺收尸了. 1.要点: 如何为兄弟抬棺回收? 分配时跟谁分开的, 回收时要跟 ...

  6. Linux 内存管理 | 地址映射:分段、分页、段页

    文章目录 分段 分页 多级页表 快表(TLB) 段页式 Linux Linux 内存管理 | 物理内存管理:内存碎片.伙伴系统.slab分配器 Linux 内存管理 | 虚拟内存管理:虚拟内存空间.虚 ...

  7. Linux内存管理之基本概念介绍(一)

    Linux内存管理之基本概念介绍(一) Linux内存管理之物理内存管理(二) Linux内存管理之内存管理单元(MMU)(三) Linux内存管理之分配掩码(四) Linux内存管理之伙伴系统(五) ...

  8. C/C++内存分配与Linux内存管理进程所涉及到的五个数据段 .

    一. 在c中分为这几个存储区 1.栈 - 由编译器自动分配释放 2.堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 3.全局区(静态区),全局变量和静态变量的存储是放在一块的, ...

  9. linux内存管理的主要概念是虚拟内存,有关linux内存管理机制的相关内容,linux物理内存和虚拟内存,深入了解Linux内存运行 ......

    在linux中空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然. 这是Linux内存管理的一个优秀特性,区别于Windows的内存管理. 主要特点: 无论物理内存有多大,L ...

最新文章

  1. lsit集合去重复 顶级表达式
  2. 220V电容启动交流电机
  3. Android测试框架-uiautomator
  4. JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
  5. 在Ubuntu 16.04下安装Matlab 2017a
  6. MessagePack Java Jackson Dataformat 在 Map 中不使用 String 为 Key 的序列化
  7. mysql 导入导出脚本_MySQL导入和导出sql脚本
  8. (88)FPGA乘法器设计(移位相加乘法器)
  9. BZOJ2243: [SDOI2011]染色
  10. 本地提交到yarn_Yarn运行Flink作业 0449
  11. SignalR主动通知订阅者示例
  12. 母机修改了文件,虚拟机复制到的可能不是预期的
  13. python服务器运维步骤_python运维服务器
  14. 适用于物联网数据共享的区块链节点存储优化方案
  15. SWMM代码移植到64位平台
  16. 抖音快手火山 热门采集/个人主页无水印视频批量解析下载工具2019-11-11
  17. c语言调用min()函数求最小值,min函数(min函数多条件求最小值)
  18. 365天历史时间顺序读经计划表
  19. python3 接入IOS推送apn
  20. SpringBoot整合Mybaits开发报java.lang.IllegalArgumentException: At least one base package must be specifie

热门文章

  1. mysql数据库初识实训总结_MySQL(数据库)的初识
  2. linux go missing git command,安装beego出现go: missing Git command
  3. docker查找镜像_5 款非常好用的开源 Docker 工具,get一波~
  4. php prepare 批量,PreparedStatement批处理
  5. 【Java基础篇】你真的懂switch语句吗?
  6. 1109: 数根(函数专题)
  7. javaBean和jsp应用
  8. 腐蚀rust服务器命令_【使用 Rust 写 Parser】2. 解析Redis协议
  9. php 验证码字体居中,自定义验证码图片的宽高后文本垂直水平居中[帝国cms ShowKey.php]-网站程序网...
  10. python 小说爬虫_从零开始写Python爬虫 --- 1.7 爬虫实践: 排行榜小说批量下载