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

简介:

转自: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博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/4837250.html,如需转载请自行联系原作者

相关文章
|
27天前
|
存储 算法 Linux
【Linux 应用开发 共享内存】深入理解和实践 ftruncate:共享内存的有效管理
【Linux 应用开发 共享内存】深入理解和实践 ftruncate:共享内存的有效管理
60 5
|
3天前
|
机器学习/深度学习 缓存 监控
linux查看CPU、内存、网络、磁盘IO命令
`Linux`系统中,使用`top`命令查看CPU状态,要查看CPU详细信息,可利用`cat /proc/cpuinfo`相关命令。`free`命令用于查看内存使用情况。网络相关命令包括`ifconfig`(查看网卡状态)、`ifdown/ifup`(禁用/启用网卡)、`netstat`(列出网络连接,如`-tuln`组合)以及`nslookup`、`ping`、`telnet`、`traceroute`等。磁盘IO方面,`iostat`(如`-k -p ALL`)显示磁盘IO统计,`iotop`(如`-o -d 1`)则用于查看磁盘IO瓶颈。
|
8天前
|
存储 缓存 监控
Java内存管理:垃圾回收与内存泄漏
【4月更文挑战第16天】本文探讨了Java的内存管理机制,重点在于垃圾回收和内存泄漏。垃圾回收通过标记-清除过程回收无用对象,Java提供了多种GC类型,如Serial、Parallel、CMS和G1。内存泄漏导致内存无法释放,常见原因包括静态集合、监听器、内部类、未关闭资源和缓存。内存泄漏影响性能,可能导致应用崩溃。避免内存泄漏的策略包括代码审查、使用分析工具、合理设计和及时释放资源。理解这些原理对开发高性能Java应用至关重要。
|
15天前
|
存储 缓存 监控
Linux内存和硬盘空间管理技巧
了解Linux内存和硬盘管理技巧,提升系统性能和稳定性。使用`free`, `top`, `vmstat`监控内存,通过`sync`, `echo 1 &gt; /proc/sys/vm/drop_caches`清理缓存。利用Swap分区释放内存。借助`df`, `du`检查硬盘空间,清理无用文件,使用`clean-old`, `gzip`, `tar`压缩归档。查找大文件用`find`和`du`,确保
33 0
|
16天前
|
Prometheus 监控 Cloud Native
【Linux】查看系统内存命令(详细讲解)
【Linux】查看系统内存命令(详细讲解)
|
20天前
|
存储 缓存 监控
深入解析linux内存指标:快速定位系统内存问题的有效技巧与实用方法(free、top、ps、vmstat、cachestat、cachetop、sar、swap、动态内存、cgroops、oom)
深入解析linux内存指标:快速定位系统内存问题的有效技巧与实用方法(free、top、ps、vmstat、cachestat、cachetop、sar、swap、动态内存、cgroops、oom)
|
23天前
|
缓存 算法 Java
Java内存管理:优化性能和避免内存泄漏的关键技巧
综上所述,通过合适的数据结构选择、资源释放、对象复用、引用管理等技巧,可以优化Java程序的性能并避免内存泄漏问题。
25 5
|
28天前
|
存储 缓存 监控
Linux 系统 内存通用指标以及查询方式
Linux 系统 内存通用指标以及查询方式
18 0
|
28天前
|
存储 Linux 程序员
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
72 0
|
28天前
|
存储 算法 Linux
深入理解Linux内存管理brk 和 sbrk 与以及使用C++ list实现内存分配器
深入理解Linux内存管理brk 和 sbrk 与以及使用C++ list实现内存分配器
34 0