Skip to main content
Linux 使用虚拟内存系统。因此,用户程序访问的地址并不直接对应硬件所使用的物理地址。虚拟内存引入了一个间接层,使程序可以分配超出物理可用内存的额外内存。 内存管理实现涵盖以下方面:
  • 管理内存中的物理页
  • 用于以大块方式分配内存的伙伴(buddy)系统
  • 用于分配较小内存块的 slab、slub 和 slob 分配器
  • 用于分配非连续内存块的 vmalloc 机制
  • 进程的地址空间

/proc 文件系统

/proc 文件系统提供以下文件:

/proc/meminfo

此文件提供有关内存分布和使用情况的信息。
  • 要查看此文件的内容,请运行以下命令:
    示例输出:
有关此文件中可用参数的更多信息,请参阅 /proc filesystem。

/proc/vmstat

此文件显示来自内核的详细虚拟内存统计信息。大多数统计信息仅在您在 init/Kconfig 文件中启用 CONFIG_VM_EVENT_COUNTERS 选项后才可用。
  • 要查看此文件的内容,请运行以下命令:
    示例输出:
有关此文件中可用参数的更多信息,请参阅 Linux 手册页。

/proc/iomem

此文件显示系统中各种设备驱动程序的内存映射。
  • 要查看此文件的内容,请运行以下命令:
    示例输出:

/proc/vmallocinfo

此文件显示通过 vmalloc 或 ioremap 进行的虚拟地址分配的详细信息。
  • 要查看此文件的内容,请运行以下命令:
    示例输出:

memblock 接口

debugfs 文件系统上的 memblock 接口提供有关系统中可用内存区域和保留内存区域的详细信息。此接口提供以下文件:

/sys/kernel/debug/memblock/memory

此文件提供 Linux 内核可见的所有可用内存区域(HLOS 和非 HLOS)的信息。要确定内核可访问的总体内存,请计算每个区域起始地址和结束地址之间的差值,并将这些值求和以得到已占用的总 RAM。剩余内存(即设备的 RAM 大小与已占用 RAM 之间的差值)是非 HLOS 内存,或由其他子系统占用的内存。
  • 要查看此文件的内容,请运行以下命令:
    示例输出:

/sys/kernel/debug/memblock/reserved

此文件提供系统中所有保留内存区域的信息。
  • 要查看此文件的内容,请运行以下命令:
    示例输出:

调试内存泄漏问题

要调试内核内存泄漏问题,请启用以下配置选项:
  • CONFIG_DEBUG_KMEMLEAK=y
  • CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE=4000
  • CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
默认情况下,内核线程每 10 分钟扫描一次内存,并打印发现的新的未被引用对象的数量。例如,
在内核命令行上传入 KMEMLEAK=off,可以在引导时禁用 KMEMLEAK 选项。 有关 kmemleak.txt 文件的更多信息,请参阅内核文档。 以下额外的内核配置选项可用于跟踪每一页内存的分配者:
  • CONFIG_PAGE_OWNER
  • CONFIG_PAGE_OWNER_ENABLE_DEFAULT
  • CONFIG_PAGE_EXTENSION
启用这些选项有助于识别多个分配,这些分配可能表明存在内存泄漏问题。

识别内存损坏问题

启用以下内核配置选项以识别内存损坏问题:
  • CONFIG_PAGE_POISONING
  • CONFIG_SLUB_DEBUG_ON
  • CONFIG_DEBUG_LIST
  • CONFIG_SLUB_DEBUG
示例日志:
有关 slub 调试的更多信息,请参阅内核文档中的 Documentation/vm/slub.txt 文件。

内存不足

当系统无法分配页面时,内核日志会显示如下消息:
这些消息表明系统无法分配所请求的页面。日志消息的第一行提供了有关内存不足问题的若干详细信息。例如,在以下日志中:
  • order:表示页面的大小。在此示例中,2 2 x PAGE_SIZE (4 K) = 16 K
    • Linux 使用伙伴分配器,以 2 的幂次分配页面。
      • 伙伴分配器的最大大小为 order 10 = 2 10 x 4 kB = 4 MB。
      • 对于 > 4 MB 的分配,请使用替代分配方法,例如连续内存分配器(CMA)。
    • 对于高阶分配失败的情况,请检查内存是否可以是虚拟连续的,而不必是物理连续的。
  • mode:表示所请求页面的类型
    • mode 提供有关获取空闲页(GFP)标志的信息。在此示例中,mode 为 0x10d2。
    • mode 是分配中所有 GFP 标志进行 OR 运算的结果。
  • 系统中可用的页面:页面分配失败消息会打印系统中可用页面大小的详细信息。

IOMMU 页面错误

输入输出内存管理单元(IOMMU),也称为系统内存管理单元(SMMU),代表没有自身 MMU 的子系统执行内存管理功能。 IOMMU 硬件模块允许物理上不连续的页面支持虚拟连续内存。IOMMU 中的内存转换逻辑与 CPU MMU 中的逻辑相同。 IOMMU 页面错误是最常见的 IOMMU 问题。当请求的页面已在页表中映射但在内存中找不到时,就会发生该错误。错误处理程序会接收 IOMMU 的上下文库(context bank)实例,并转储该上下文的寄存器。 以下日志表明发生了 IOMMU 页面错误。
下表描述了日志消息中捕获的字段。 表:IOMMU 页面错误日志中的信息
  • 转换错误(TF)
  • 访问权限错误(APF)
  • 停滞状态(SS)
FSR 是 IOMMU 调试中最重要的寄存器之一。此寄存器具有读/写清除访问权限。对此寄存器的读操作会读取寄存器中的值,而写操作会清除与写入数据中 1 对应的位,并保持与 0 对应的位不变。此过程可防止在写入寄存器以清除旧故障时无意中清除新故障。此寄存器中一些有用的位包括: 表:故障状态寄存器中的位 TF、APF 和 SL 标志表示正常运行,而 TLBMF、HTWDEEF、HTWSEEF 和 MHF 标志表示存在问题。

IOMMU 页表

IOMMU 页表转储在内核日志中提供来自 FAR 的故障地址和寄存器转储。此故障地址代表虚拟地址,您可以从页表中获取对应的物理地址。从页表转储中,您可以确定所请求的地址是否已映射。每个 IOMMU 域都有一个页表,转储中包含每个域的页表。目前有六个域。 以下是 Domain: 2 页表的示例转储。
在此示例中,第一列代表虚拟地址,第二列代表对应的连续物理地址区域中的字节数,第三列代表物理地址。每个区域还标注了相应的权限。

内存映射

有关内存映射的更多信息,请参阅最新的发行说明。

栈损坏

错误的编码逻辑会访问栈中的内存位置,导致这些内存位置上的值发生变化,从而造成栈损坏。栈损坏可能以下列方式发生:
  • 由于错误的代码逻辑,程序耗尽了所有栈内存并写入栈边界之外的内存,导致栈溢出。
  • 访问越界的数组。
  • 未定义或已释放的指针指向栈地址。
  • 调用者函数的返回地址被破坏。
要识别栈损坏问题,请启用以下内核配置选项:
  • CONFIG_STACKPROTECTOR
  • CONFIG_STACKPROTECTOR_STRONG
内核地址消毒器(KASAN)实用工具也有助于识别某些栈损坏问题。