4. 内存管理调优:mem、memmap、crashkernel 参数详解与实战配置

内存是 Linux 系统最核心的资源之一。内核引导参数中的 mem、memmap 和 crashkernel 直接决定了操作系统可用的物理内存范围、内存区域的划分方式以及内核崩溃转储机制的预留空间。错误配置会导致系统无法识别全部内存、设备驱动 DMA 冲突,甚至无法捕获内核崩溃现场。本章从参数语义、配置语法、实战场景三个维度进行深度解析。

4.1 mem 参数:限制内核可见物理内存

mem 参数用于告诉内核只使用指定大小的物理内存,超出部分将被忽略。该参数在内存测试、隔离坏内存区域、模拟低内存环境等场景中非常实用。

4.1.1 语法与行为

参数格式 说明 示例
mem=nn[KMG] 限制内核可见内存总量为 nn mem=4G
mem=nn[KMG]@ss 从物理地址 ss 开始,使用 nn 大小内存 mem=512M@0x10000000
⚠ 重要警告: 使用 mem= 限制内存后,内核不会访问被隐藏的物理地址空间。如果该区域被设备 DMA 或 BIOS 使用,可能导致系统不稳定或设备无法初始化。生产环境慎用。

4.1.2 实战场景:隔离坏内存区域

假设服务器物理内存 32 GB,但地址 0x20000000 ~ 0x30000000(256 MB)存在硬件故障。可通过 mem= 参数让内核跳过该区域:

# 在 GRUB 配置中添加
GRUB_CMDLINE_LINUX="mem=31.75G"
# 或更精确地指定可用区域
GRUB_CMDLINE_LINUX="mem=512M@0x0 mem=31G@0x30000000"

上述配置让内核使用 0x0 ~ 0x20000000(512 MB)和 0x30000000 ~ 结束(31 GB),跳过故障区间。

4.1.3 验证方法

# 查看内核实际识别内存
$ dmesg | grep -i "memory"
[    0.000000] Memory: 32883020K/33554432K available

# 查看 /proc/meminfo
$ grep MemTotal /proc/meminfo
MemTotal:       32883020 kB
💡 调优提示: 在虚拟化或容器宿主机上,使用 mem= 可以模拟低内存压力测试,验证 OOM Killer 行为和应用程序的内存容错能力。
mem 参数物理内存区域划分 完整物理内存 0x0 ~ 0x80000000 (2 GB) 故障区域 (256 MB) mem= 跳过此区域 区域 A: 512 MB 区域 B: 1.25 GB 配置: mem=512M@0x0 mem=1280M@0x30000000

4.2 memmap 参数:精确内存区域映射与保留

memmap 参数提供了比 mem 更精细的内存区域控制能力,允许将特定物理地址区间标记为保留、可用或特定用途。该参数在嵌入式系统、UEFI 固件兼容性修复、大页内存预分配等场景中不可或缺。

4.2.1 语法格式

格式 含义 典型用途
memmap=nn[KMG]$ss 从 ss 开始保留 nn 大小内存(内核不可用) 保留给固件或硬件设备
memmap=nn[KMG]!ss 从 ss 开始标记 nn 大小为可用内存 覆盖 BIOS 错误的内存映射
memmap=nn[KMG]#ss 从 ss 开始预留 nn 大小给特定驱动 DMA 缓冲区预留

4.2.2 实战:修复 UEFI 内存映射冲突

某些 UEFI 固件会将 ACPI 数据区域错误地报告为可用内存,导致内核在写入时损坏 ACPI 表。使用 memmap 强制保留该区域:

# 保留 0x7FE00000 ~ 0x7FFFFFFF (2 MB) 给 ACPI
GRUB_CMDLINE_LINUX="memmap=2M$0x7FE00000"

4.2.3 实战:为大页预留连续物理内存

数据库或 HPC 应用需要 1 GB 大页时,要求物理内存连续。通过 memmap 提前预留:

# 在 4 GB 边界预留 1 GB 连续内存
GRUB_CMDLINE_LINUX="memmap=1G$0x100000000"

# 启动后验证预留区域
$ dmesg | grep "reserved"
[    0.000000] Reserved memory: created CMA memory pool at 0x100000000, size 1024 MiB
📌 关键区别: mem= 是“限制可见总量”,memmap= 是“精确控制每个区域的属性”。前者适合快速裁剪,后者适合精细调优。
memmap 参数内存区域操作流程 原始物理内存布局(BIOS/UEFI 报告) ACPI 坏块 保留 memmap 参数处理 内核最终可用内存布局 保留(ACPI) 跳过(坏块) 保留(驱动) memmap 操作符说明 • $ 保留区域:内核不可见,用于固件/ACPI • ! 强制可用:覆盖 BIOS 错误标记 • # 驱动预留:为 DMA/大页预留连续空间

4.3 crashkernel 参数:内核崩溃转储预留

crashkernel 参数用于在系统启动时预留一段物理内存,供 kdump 机制在内核崩溃时加载捕获内核(capture kernel)并保存 vmcore 文件。没有正确配置 crashkernel,内核 panic 后将无法自动转储,导致问题排查无据可依。

4.3.1 参数格式与推荐值

格式 说明 推荐值(x86_64)
crashkernel=size[KMG] 在低端内存预留固定大小 crashkernel=256M
crashkernel=size[KMG]@offset 在指定偏移地址预留 crashkernel=256M@0x40000000
crashkernel=range1:size1,... 根据总内存范围自动选择预留大小 crashkernel=2G-4G:256M,4G-32G:512M
crashkernel=auto 内核自动计算预留大小 依赖架构和总内存

4.3.2 实战:为生产服务器配置 crashkernel

对于 64 GB 内存的生产数据库服务器,推荐使用范围格式:

# /etc/default/grub
GRUB_CMDLINE_LINUX="crashkernel=4G-64G:512M,64G-:1G"

# 更新 GRUB 配置
$ grub2-mkconfig -o /boot/grub2/grub.cfg

# 重启后验证预留
$ dmesg | grep -i "crash"
[    0.000000] Reserving 512MB of memory at 256MB for crashkernel

# 查看 kdump 服务状态
$ systemctl status kdump
● kdump.service - Crash recovery kernel arming
   Loaded: loaded (/usr/lib/systemd/system/kdump.service; enabled)
   Active: active (exited)

4.3.3 预留大小计算原则

  • 捕获内核自身内存:通常需要 64 MB ~ 256 MB,取决于内核模块数量。
  • vmcore 保存缓冲区:需要容纳被捕获内核的内存映像,建议为总内存的 1/64 ~ 1/32。
  • 硬件保留区域:某些设备需要 DMA 连续内存,预留时需额外考虑。
⚠ 常见陷阱: 预留过小会导致 kdump 无法加载捕获内核;预留过大会浪费生产内存。对于内存小于 4 GB 的系统,建议使用 crashkernel=128M;4 GB ~ 64 GB 使用 crashkernel=256M 或 512M;超过 64 GB 使用 1G。
crashkernel 预留与 kdump 工作流程 正常运行时:生产内核使用全部内存 crashkernel 预留 内核 Panic 崩溃后:生产内核停止,捕获内核启动 捕获内核 保存 vmcore vmcore 保存到磁盘 /var/crash/<timestamp>/ crashkernel 预留区域在正常运行时完全空闲,仅在崩溃时被捕获内核使用

4.4 三个参数的协同配置与冲突避免

在实际生产环境中,mem、memmap 和 crashkernel 可能同时出现在引导参数中。错误的组合顺序或地址重叠会导致系统启动失败或功能异常。

4.4.1 参数处理顺序

内核在启动早期按以下顺序解析内存相关参数:

  1. 先处理 memmap=:建立初始物理内存区域属性表。
  2. 再处理 mem=:在区域表基础上裁剪可见内存总量。
  3. 最后处理 crashkernel=:在最终可用内存中预留转储空间。

4.4.2 冲突场景与解决方案

冲突场景 后果 解决方案
mem= 限制区域覆盖了 crashkernel= 预留地址 crashkernel 预留失败,kdump 不可用 先使用 memmap= 确保预留区域不被裁剪
memmap= 保留区域与 crashkernel= 重叠 内核 panic 或启动卡死 调整 crashkernel=@offset 避开保留区域
mem= 设置过小,无法容纳 crashkernel= 系统可用内存不足,OOM 频繁 增大 mem= 或减小 crashkernel=

4.4.3 生产环境推荐配置模板

# 64 GB 内存服务器,无坏内存,需要 kdump
GRUB_CMDLINE_LINUX="crashkernel=4G-64G:512M,64G-:1G"

# 32 GB 内存服务器,存在 128 MB 坏内存区域
GRUB_CMDLINE_LINUX="memmap=128M$0x20000000 crashkernel=256M"

# 16 GB 内存虚拟机,模拟 8 GB 环境并启用 kdump
GRUB_CMDLINE_LINUX="mem=8G crashkernel=128M@0x40000000"
🔧 验证命令汇总:
dmesg | grep -E "memory|Memory|crash|reserved" — 查看内存识别与预留
cat /proc/iomem | grep -E "Kernel|Crash|Reserved" — 查看物理地址空间分配
kdumpctl status — 检查 kdump 服务是否就绪
free -h — 确认系统可用内存符合预期
mem / memmap / crashkernel 协同处理流程 步骤 1 memmap= 解析 步骤 2 mem= 裁剪 步骤 3 crashkernel= 预留 最终内存布局:可用区域 + 保留区域 + crashkernel 区域 顺序不可颠倒:memmap 建立区域表 → mem 裁剪总量 → crashkernel 在最终可用区预留

4.5 本章小结

  • mem= 用于限制内核可见内存总量,适合内存测试和坏内存隔离,但会隐藏所有超出部分。
  • memmap= 提供精细的区域属性控制,支持保留、强制可用、驱动预留三种操作,是解决固件兼容性和大页预留的首选工具。
  • crashkernel= 为 kdump 预留转储空间,生产环境必须配置,推荐使用范围格式自动适配不同内存容量。
  • 三个参数按 memmap → mem → crashkernel 顺序处理,配置时需避免地址重叠和容量冲突。
  • 每次修改引导参数后,务必通过 dmesg、/proc/iomem 和 kdumpctl status 验证配置生效。