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

简介:
 
 

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博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/5660218.html,如需转载请自行联系原作者
相关文章
|
3月前
|
监控 Linux 开发者
理解Linux操作系统内核中物理设备驱动(phy driver)的功能。
综合来看,物理设备驱动在Linux系统中的作用是至关重要的,它通过与硬件设备的紧密配合,为上层应用提供稳定可靠的通信基础设施。开发一款优秀的物理设备驱动需要开发者具备深厚的硬件知识、熟练的编程技能以及对Linux内核架构的深入理解,以确保驱动程序能在不同的硬件平台和网络条件下都能提供最优的性能。
209 0
|
缓存 监控 Linux
在Linux中,如何看当前系统有几颗物理CPU和每颗CPU的核数?
在Linux中,如何看当前系统有几颗物理CPU和每颗CPU的核数?
|
10月前
|
存储 监控 算法
Java内存管理深度剖析:从垃圾收集到内存泄漏的全面指南####
本文深入探讨了Java虚拟机(JVM)中的内存管理机制,特别是垃圾收集(GC)的工作原理及其调优策略。不同于传统的摘要概述,本文将通过实际案例分析,揭示内存泄漏的根源与预防措施,为开发者提供实战中的优化建议,旨在帮助读者构建高效、稳定的Java应用。 ####
173 35
|
11月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
184 6
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
335 31
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
存储 安全 程序员
【C++篇】深入内存迷宫:C/C++ 高效内存管理全揭秘
【C++篇】深入内存迷宫:C/C++ 高效内存管理全揭秘
675 3
在 ArkTS 中,如何有效地进行内存管理和避免内存泄漏?
【9月更文挑战第25天】在ArkTS中,有效进行内存管理并避免内存泄漏的方法包括:及时释放不再使用的资源,如关闭监听器和清理定时器;避免循环引用,通过弱引用打破循环;合理使用单例模式,确保单例对象正确释放;及时处理不再使用的页面和组件,在卸载时清理相关资源。
483 9
|
存储 缓存 监控
深入了解MySQL内存管理:如何查看MySQL使用的内存
深入了解MySQL内存管理:如何查看MySQL使用的内存
1203 1
|
存储 Java 程序员
JVM自动内存管理之运行时内存区
这篇文章详细解释了JVM运行时数据区的各个组成部分及其作用,有助于理解Java程序运行时的内存布局和管理机制。
JVM自动内存管理之运行时内存区

热门文章

最新文章