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,如需转载请自行联系原作者
相关文章
|
1月前
|
缓存 Java Linux
如何解决 Linux 系统中内存使用量耗尽的问题?
如何解决 Linux 系统中内存使用量耗尽的问题?
140 48
|
24天前
|
存储 监控 算法
Java内存管理深度剖析:从垃圾收集到内存泄漏的全面指南####
本文深入探讨了Java虚拟机(JVM)中的内存管理机制,特别是垃圾收集(GC)的工作原理及其调优策略。不同于传统的摘要概述,本文将通过实际案例分析,揭示内存泄漏的根源与预防措施,为开发者提供实战中的优化建议,旨在帮助读者构建高效、稳定的Java应用。 ####
37 8
|
21天前
|
算法 Linux
深入探索Linux内核的内存管理机制
本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。
|
1月前
|
缓存 Ubuntu Linux
Linux环境下测试服务器的DDR5内存性能
通过使用 `memtester`和 `sysbench`等工具,可以有效地测试Linux环境下服务器的DDR5内存性能。这些工具不仅可以评估内存的读写速度,还可以检测内存中的潜在问题,帮助确保系统的稳定性和性能。通过合理配置和使用这些工具,系统管理员可以深入了解服务器内存的性能状况,为系统优化提供数据支持。
38 4
|
1月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
29天前
|
存储 算法 安全
深入理解Linux内核的内存管理机制
本文旨在深入探讨Linux操作系统内核的内存管理机制,包括其设计理念、实现方式以及优化策略。通过详细分析Linux内核如何处理物理内存和虚拟内存,揭示了其在高效利用系统资源方面的卓越性能。文章还讨论了内存管理中的关键概念如分页、交换空间和内存映射等,并解释了这些机制如何协同工作以提供稳定可靠的内存服务。此外,本文也探讨了最新的Linux版本中引入的一些内存管理改进,以及它们对系统性能的影响。
|
1月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
110 8
|
1月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
402 6
|
1月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
90 3
|
1月前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
80 2

热门文章

最新文章