Linux内存管理--物理内存分配【转】

简介: 转自:http://blog.csdn.net/myarrow/article/details/8682819 1. First Fit分配器     First Fit分配器是最基本的内存分配器,它使用bitmap而不是空闲块列表来表示内存。

转自: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 plain copy
 
  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 plain copy
 
  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.   
  8. #define alloc_bootmem(x) \  
  9.     __alloc_bootmem(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)  
  10. #define alloc_bootmem_align(x, align) \  
  11.     __alloc_bootmem(x, align, BOOTMEM_LOW_LIMIT)  
  12. #define alloc_bootmem_nopanic(x) \  
  13.     __alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)  
  14. #define alloc_bootmem_pages(x) \  
  15.     __alloc_bootmem(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)  
  16. #define alloc_bootmem_pages_nopanic(x) \  
  17.     __alloc_bootmem_nopanic(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)  
  18. #define alloc_bootmem_node(pgdat, x) \  
  19.     __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)  
  20. #define alloc_bootmem_node_nopanic(pgdat, x) \  
  21.     __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)  
  22. #define alloc_bootmem_pages_node(pgdat, x) \  
  23.     __alloc_bootmem_node(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)  
  24. #define alloc_bootmem_pages_node_nopanic(pgdat, x) \  
  25.     __alloc_bootmem_node_nopanic(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)  
  26.   
  27. #define alloc_bootmem_low(x) \  
  28.     __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0)  
  29. #define alloc_bootmem_low_pages(x) \  
  30.     __alloc_bootmem_low(x, PAGE_SIZE, 0)  
  31. #define alloc_bootmem_low_pages_node(pgdat, x) \  
  32.     __alloc_bootmem_low_node(pgdat, x, PAGE_SIZE, 0)  

 

 

2.4 释放内存

     调用free_bootmem来释放内存。

 

[cpp]  view plain copy
 
    1. void __init free_bootmem(unsigned long addr, unsigned long size)  
    2. {  
    3.     unsigned long start, end;  
    4.   
    5.     kmemleak_free_part(__va(addr), size);  
    6.   
    7.     start = PFN_UP(addr);  
    8.     end = PFN_DOWN(addr + size);  
    9.   
    10.     mark_bootmem(start, end, 0, 0);  
    11. }  
【作者】 张昺华
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
目录
相关文章
|
8月前
|
缓存 监控 Linux
在Linux中,如何看当前系统有几颗物理CPU和每颗CPU的核数?
在Linux中,如何看当前系统有几颗物理CPU和每颗CPU的核数?
|
4月前
|
存储 监控 算法
Java内存管理深度剖析:从垃圾收集到内存泄漏的全面指南####
本文深入探讨了Java虚拟机(JVM)中的内存管理机制,特别是垃圾收集(GC)的工作原理及其调优策略。不同于传统的摘要概述,本文将通过实际案例分析,揭示内存泄漏的根源与预防措施,为开发者提供实战中的优化建议,旨在帮助读者构建高效、稳定的Java应用。 ####
74 8
|
5月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
110 6
|
6月前
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
6月前
|
存储 安全 程序员
【C++篇】深入内存迷宫:C/C++ 高效内存管理全揭秘
【C++篇】深入内存迷宫:C/C++ 高效内存管理全揭秘
265 3
|
6月前
|
存储 缓存 监控
深入了解MySQL内存管理:如何查看MySQL使用的内存
深入了解MySQL内存管理:如何查看MySQL使用的内存
848 1
|
7月前
|
Java
在 ArkTS 中,如何有效地进行内存管理和避免内存泄漏?
【9月更文挑战第25天】在ArkTS中,有效进行内存管理并避免内存泄漏的方法包括:及时释放不再使用的资源,如关闭监听器和清理定时器;避免循环引用,通过弱引用打破循环;合理使用单例模式,确保单例对象正确释放;及时处理不再使用的页面和组件,在卸载时清理相关资源。
280 9
|
7月前
|
监控 Java 大数据
【Java内存管理新突破】JDK 22:细粒度内存管理API,精准控制每一块内存!
【9月更文挑战第9天】虽然目前JDK 22的确切内容尚未公布,但我们可以根据Java语言的发展趋势和社区的需求,预测细粒度内存管理API可能成为未来Java内存管理领域的新突破。这套API将为开发者提供前所未有的内存控制能力,助力Java应用在更多领域发挥更大作用。我们期待JDK 22的发布,期待Java语言在内存管理领域的持续创新和发展。
|
7月前
|
存储 并行计算 算法
CUDA统一内存:简化GPU编程的内存管理
在GPU编程中,内存管理是关键挑战之一。NVIDIA CUDA 6.0引入了统一内存,简化了CPU与GPU之间的数据传输。统一内存允许在单个地址空间内分配可被两者访问的内存,自动迁移数据,从而简化内存管理、提高性能并增强代码可扩展性。本文将详细介绍统一内存的工作原理、优势及其使用方法,帮助开发者更高效地开发CUDA应用程序。
|
6月前
|
Java C语言 iOS开发
MacOS环境-手写操作系统-16-内存管理 解析内存状态
MacOS环境-手写操作系统-16-内存管理 解析内存状态
80 0