日常开发过程可能要预留一段物理内存出来提供特殊场景使用(独占一段内存不被系统所使用)。

本文讲解3种预留内存的方法,以及对预留内存的使用。


文章目录

  • 一、memblock方式预留内存
    • 1.1 memblock内存管理
    • 1.2 memblock 方式预留内存方法
    • 1.3 预留内存访问
  • 二、 限制内存总空间方式预留内存
    • 2.1 预留内存方法
    • 2.2 预留内存访问
  • 三、CMA连续内存分配方式预留内存

一、memblock方式预留内存

1.1 memblock内存管理

mmeblock是内存的一种管理机制,主要管理这两种内存:一种是系统可用部分的物理内存(usable),也就是/proc/meminfo里看到的总内存都是提供给系统使用的;另一种是用户预留部分的内存(reserved),用户自己特殊使用,这部分在系统总内存里看不到,本文主要讲解该部分内存怎么预留。

memblock 结构体维护着上述两种内存, 其中成员 memory 维护着可用物理内存区域;成员 reserved 维护预留的内存区域。

struct memblock {bool bottom_up;  /* is bottom up direction? */phys_addr_t current_limit;struct memblock_type memory;    //维护着可用物理内存区域struct memblock_type reserved;  //维护着预留的内存区域
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAPstruct memblock_type physmem;
#endif
};

如下这篇对memblock原理讲解的很详细

https://biscuitos.github.io/blog/MMU-ARM32-MEMBLOCK-memblock_reserve/

我们在系统下也可以看到这两种内存的分布情况。
1、dmesg的e820里打印了内存分布情况,可以看到usable和 reserved两种标注的内存块。

  • usable:就是系统可用部分的物理内存(System RAM)。
  • reserved: 就是预留部分的内存。
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009ebff] usable
[    0.000000] BIOS-e820: [mem 0x000000000009ec00-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000dc000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000bfecffff] usable
[    0.000000] BIOS-e820: [mem 0x00000000bfed0000-0x00000000bfefefff] ACPI data
[    0.000000] BIOS-e820: [mem 0x00000000bfeff000-0x00000000bfefffff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bff00000-0x00000000bfffffff] usable
[    0.000000] BIOS-e820: [mem 0x00000000f0000000-0x00000000f7ffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec0ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fffe0000-0x00000000ffffffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000013fffffff] usable

2、或者在cat /proc/iomem |grep 'System RAM’的 io内存分布里也能看到系统可用部分的物理内存的分布情况。4段System RAM加起来就是总的可用物理内存。


[root@localhost ~]# cat /proc/iomem |grep 'System RAM'
00001000-0009ebff : System RAM
00100000-bfecffff : System RAM
bff00000-bfffffff : System RAM
100000000-13fffffff : System RAM

1.2 memblock 方式预留内存方法

方法很简单,通过memblock_reserve() 将一段物理内存放在预留区里,在setup.c中setup_arch启函数中添加,内核补丁如下(基于:linux3.10.0-123.):

diff -uNrp a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
--- a/arch/x86/kernel/setup.c   2021-01-29 23:09:08.443072526 -0800
+++ b/arch/x86/kernel/setup.c   2021-01-29 23:31:53.521307672 -0800
@@ -907,6 +907,8 @@ static void rh_check_supported(void)void __init setup_arch(char **cmdline_p){+
+        struct memblock_region *reg;memblock_reserve(__pa_symbol(_text),(unsigned long)__bss_stop - (unsigned long)_text);@@ -1035,6 +1037,13 @@ void __init setup_arch(char **cmdline_p)* again from within noexec_setup() during parsing early parameters* to honor the respective command line option.*/
+
+         memblock_reserve(0x100000000, 0x2000000);
+        pr_info("Scan equal region:\n");
+        for_each_memblock(reserved, reg)  //遍历打印reserved所有分区
+                pr_info("Region [%llx -- %llx]\n", (u64)(reg->base),
+                        (u64)(reg->base + reg->size));
+x86_configure_nx();parse_early_param();

memblock_reserve(0x100000000, 0x2000000);函数完成了对ram起始地址0x100000000开始保留32MB(0x2000000)内存。reserved链表管理着预留区域的内存,memblock_reserve会将预留内存段插入链表新节点里(如果出现reserve之间地址相互覆盖的,reserver会将它们合并成一个内存区,即一个节点)。for_each_memblock()可以获取每个预留区内存信息并打印。

该方式是否成功预留出内存,可以在dmesg中查看打印,如果要查看memblock调试打印信息,可以在grub中加入:memblock=debug。

但实际测试,在e820和iomem里并没有显现该区域内存信息。猜测是memblock_reserve()没有把内存块纳入e820管理中,有待研究。

1.3 预留内存访问

通常访问指定物理地址的内存方式有很多种,如:

memremap / ioramp 方式将其映射
phy_to_vir 线性映射虚拟地址
mmap方式将物理地址映射到用户空间

通过实际测试, memblock_reserve保留的内存段,可以采用memremap ,phy_to_vir 方式将物理地址映射出并使用。


二、 限制内存总空间方式预留内存

2.1 预留内存方法

该方法比较简单,直接修改系统grub启动参数,将系统总内存限制在指定大小,使得其余内存不可见。然后对不可见内存进行申请保留。

[root@localhost ~]# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.10.0-123.el7.x86_64 root=UUID=79704805-e306-420b-827a-52849e1376c1 ro vconsole.keymap=us crashkernel=auto vconsole.font=latarcyrheb-sun16 rhgb quiet LANG=en_US.UTF-8 mem=1G

如上mem=2G ,是限制了可用物理内存为2G,那么我们可以对[2-4G]内的内存进行申请,映射和使用。
在iomem和meminfo里可以看到系统可用总内存已经减少2G左右


[root@localhost ~]# cat /proc/iomem |grep RAM
00001000-0009ebff : System RAM
00100000-3fffffff : System RAM
100000000-13fffffff : System RAM

e820里可以显示到全部(包括隐藏)的内存情况,usable是对应的物理内存,比对iomem中的RAM部分,可知隐藏掉的部分(预留)内存为:[3fffffff—bfecffff], [bff00000–bfffffff]。 大约2G左右


[root@localhost ~]# dmesg |grep e820
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009ebff] usable
[    0.000000] BIOS-e820: [mem 0x000000000009ec00-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000dc000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000bfecffff] usable
[    0.000000] BIOS-e820: [mem 0x00000000bfed0000-0x00000000bfefefff] ACPI data
[    0.000000] BIOS-e820: [mem 0x00000000bfeff000-0x00000000bfefffff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bff00000-0x00000000bfffffff] usable
[    0.000000] BIOS-e820: [mem 0x00000000f0000000-0x00000000f7ffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec0ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fffe0000-0x00000000ffffffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000013fffffff] usable

2.2 预留内存访问

对预留部分内存访问的驱动代码如下,从0x40000000开始,申请512MB(0x20000000)内存。

static char data[] = "123456\n";
static void* addr;static int __init ram_reserve_init(void)
{if (!request_mem_region(0x40000000, 0x20000000, "reserve test")) //请求不可见的内存段权限(即:检查你申请的资源是否可用,如果可用,则将其标志为被使用。非必须){printk("request_mem_region fail\n");return - EBUSY;}addr = memremap(0x40000000, 0x20000000, MEMREMAP_WB); //映射内存空间memcpy(addr, data, sizeof(str));                   //拷贝测试数据 printk( "%s: %s\n " , __func__, ( char * )addr);//读出内存数据return 0;
}static void __exit ram_reserve_exit(void)
{iounmap(addr);release_mem_region(RESERVE_PHY, RESERVE_SIZE);pr_info(KBUILD_MODNAME ": unloaded.\n");
}module_init(ram_reserve_init);module_exit(ram_reserve_exit);

request_mem_region() 检查你申请的资源是否可用,如果可用,则将其标志为被使用,如果该内存区已经被标记,会返回报错,该调用可以忽略,建议加上。加载驱动后,通过/proc/iomem 可以查看到reserve test段的内存分配信息

该方式有个缺点就是预留的内存是ram空间的尾部,边界不确定性,可能无法准确预留出指定大小的内存。

通过实际测试,不可见内存段保留方式,不能通过phy_to_vir 方式进行映射,因为phy_to_vir 只限在normal区的内存,不可见的内存段在系统认为不在normal区中,但可以采用memremap访问 。


三、CMA连续内存分配方式预留内存

cma(contiguous memory allocation)是linux中一种动态分配连续物理内存的方式,可认为是传统kmalloc的升级版,伙伴管理系统中,kmalloc最大只能申请4M内存,开启了cma后可以申请大块的连续内存区域,该方式是先将cma部分内存从系统预留出来,当要使用时单独从cma里面动态申请大小,因此申请时候不能指定其申请地址。cma机制需要修改内核编译参数(或修改设备树)进行部署才能使用,篇幅较长,后续文章中讲解。

内存管理(二)-- linux 预留内存几种方法相关推荐

  1. 【Linux 内核 内存管理】Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )

    文章目录 一.ARM64 架构体系内存分布 二.Linux 内核启动源码 start_kernel 三.内存初始化源码 mm_init 四.内存初始化源码 mem_init 一.ARM64 架构体系内 ...

  2. 【Linux 内核 内存管理】Linux 内核内存布局 ③ ( Linux 内核 动态分配内存 系统接口函数 | 统计输出 vmalloc 分配的内存 )

    文章目录 一.Linux 内核 动态分配内存 系统接口函数 二.统计输出 vmalloc 分配的内存 一.Linux 内核 动态分配内存 系统接口函数 Linux 内核 " 动态分配内存 & ...

  3. 【Linux 内核 内存管理】Linux 内核内存布局 ② ( x86_64 架构体系内存分布 | 查看 /proc/meminfo 文件 | /proc/meminfo 重要字段解析 )

    文章目录 一.查看 x86_64 架构体系内存分布 二./proc/meminfo 重要字段解析 一.查看 x86_64 架构体系内存分布 执行 cat /proc/meminfo 命令 , 可以查看 ...

  4. linux内存管理简介,Linux操作系统的内存管理特性简介 (3)

    输出的第一行(Mem:)显示出物理内存的使用情况.总和(total)列中并没有显示出被内核使用的内存,它通常将近一兆字节.已用列(used column)显示出已用内存的总和(第二行没有把缓冲算进来) ...

  5. linux内存管理 简介,Linux操作系统的内存管理特性简介 (4)

    高速缓冲 与访问(真正的)的内存相比,磁盘[3]的读写是很慢的.另外,在相应较短的时间内多次读磁盘同样的部分也是常有的事.例如,某人也许首先阅读了一段e-mail消息,然后为了答复又将这段消息读入编辑 ...

  6. 【Linux 内核 内存管理】Linux 内核内存布局 ① ( 查看 Linux 操作系统位数 | 查看 Linux 操作系统软硬件信息 )

    文章目录 一.查看 Linux 操作系统位数 二.查看 Linux 操作系统软硬件信息 一.查看 Linux 操作系统位数 在 646464 位的 Linux 中 , 使用 484848 位 表示 & ...

  7. LINUX预留内存的实现

    在LINUX应用开发中,可能需要使用连续的物理地址来存储一些数据或者进行DMA操作,但是由于LINUX具备MMU功能,MMU模块会自动的将物理地址与虚拟地址之间建立页表对应关系(但并不是线性对应),用 ...

  8. linux内存管理子系统采用基于内存区域,Linux 内存管理之highmem简介

    一.Linux内核地址空间 一般来说Linux 内核按照 3:1 的比率来划分虚拟内存(X86等):3 GB 的虚拟内存用于用户空间,1GB 的内存用于内核空间.当然有些体系结构如MIPS使用2:2 ...

  9. 【Linux 内核 内存管理】内存管理架构 ② ( 用户空间内存管理 | malloc | ptmalloc | 内核空间内存管理 | sys_brk | sys_mmap | sys_munmap)

    文章目录 一.用户空间内存管理 ( malloc / free / ptmalloc / jemalloc / tcmalloc ) 二.内核空间内存管理 1.内核内存管理系统调用 ( sys_brk ...

最新文章

  1. HBase 与 MapReduce 集成
  2. echarts label加边框_关于echarts的lines中的label的设置 -问答-阿里云开发者社区-阿里云...
  3. html 和 body标签的 css 设置
  4. web项目实现mysql增删改查并从前端页面操作
  5. 用Python实现智能推荐!某音,某宝都是智能推荐的,你都知道吗?
  6. [活动]《博客园精华集》设计模式分册第2轮筛选结果公示
  7. Open3d之RGBD测程法
  8. 为什么我keepalive配置的vip不能通_企业十大应用-Keepalived-配置详解
  9. 2022-07-08 Unity Json2——LitJson
  10. 关于图书管理系统项目的大概思路
  11. 上海计算机一级excel试题及答案,2016年计算机一级excel试题及答案
  12. linux导入表dmp文件命令,linux下导入.dmp文件
  13. 微博微信QQ等开发者平台注册应用时提交签名信息的坑点。
  14. Analyzing the Linux boot process-分析Linux启动过程
  15. 汽车芯片TJA1057GTK/3高速 CAN 收发器3 毫米 x 3 毫米 x 0.85 毫米
  16. K_A02_001 基于单片机驱动4位数码管模块(74HC595) 0-3滚动+ 时钟显示
  17. 基于STM32F103平台的ADS79xx系列ADC(TI公司)应用方案
  18. 8口千兆工业级以太网光纤收发器 4光4电全千兆导轨式工业以太网交换机 宽温交换机
  19. MySQL数据库中常用SQL语句
  20. 时隔多年,我胡汉三又回来了(大学毕业篇-迷茫)

热门文章

  1. 网络人帮助小孩戒除网瘾
  2. / Vijos / 题库 / 1404 遭遇战 spfa 建图
  3. IIS设置允许跨域请求
  4. 字体 居中 html代码怎么写,文字和图片居中的HTML代码怎么写?
  5. Android代码打包一个apk,Android Studio 打包生成apk(示例代码)
  6. AI快车道PaddleNLP系列直播课2|开箱即用的产业级NLP开发库
  7. 中科大 2019 大数据学院 计算机专业 复试经验分享(一)
  8. Java从入门到放弃篇1
  9. java开源 VR全景商城 saas商城 b2b2c商城 o2o商城 积分商城 秒杀商城 拼团商城 分销商城 短视频商城
  10. uni-app读写文件