# 评估内存使用情况

Linux 使用虚拟内存系统。因此，用户程序访问的地址并不对应于硬件直接使用的物理地址。虚拟内存引入了一个间接层，允许程序分配超出物理可用内存的额外内存。

内存管理实现涵盖以下几个方面：

- 内存中物理页面的管理
- 分配大块内存的伙伴系统
- 分配小块内存的 slab、slub、slob 分配器
- 分配不连续内存块的 vmalloc 机制
- 进程的地址空间

## /proc 文件系统

`/proc` 文件系统提供以下文件：

- [/proc/meminfo](https://docs.qualcomm.com/doc/80-70029-12SC/topic/proc_fs.html#proc-meminfo)
- [/proc/vmstat](https://docs.qualcomm.com/doc/80-70029-12SC/topic/proc_fs.html#proc-vmstat)
- [/proc/iomem](https://docs.qualcomm.com/doc/80-70029-12SC/topic/proc_fs.html#proc-iomem)
- [/proc/vmallocinfo](https://docs.qualcomm.com/doc/80-70029-12SC/topic/proc_fs.html#proc-vmallocinfo)

### /proc/meminfo

此文件提供有关内存分配和使用情况的信息。

- 要查看此文件的内容，可运行以下命令：

> 
> 
> cat /proc/meminfo
>         Copy to clipboard
> 
> 
> **示例输出：**
> 
> 
> MemTotal:        3813532 kB
>         MemFree:          624836 kB
>         MemAvailable:    2098008 kB
>         Buffers:           40416 kB
>         Cached:          1484320 kB
>         SwapCached:            0 kB
>         Active:          1334816 kB
>         .
>         .
>         .
>         .
>         NFS_Unstable:          0 kB
>         Bounce:                0 kB
>         WritebackTmp:          0 kB
>         CommitLimit:     2431048 kB
>         Committed_AS:   99995284 kB
>         VmallocTotal:  258867136 kB
>         VmallocUsed:           0 kB
>         VmallocChunk:          0 kB
>         CmaTotal:         163840 kB
>         CmaFree:            1368 kB
>         Copy to clipboard

有关此文件中可用参数的更多信息，请参阅 [/proc filesystem](https://docs.kernel.org/filesystems/proc.html)。

### /proc/vmstat

此文件显示来自内核的详细虚拟内存统计数据。仅当您在 `init/Kconfig` 文件中启用 `CONFIG_VM_EVENT_COUNTERS` 选项时，大多数统计信息才可用。

- 要查看此文件的内容，可运行以下命令：

> 
> 
> cat /proc/vmstat
>         Copy to clipboard
> 
> 
> **示例输出：**
> 
> 
> nr_free_pages 156290
>         nr_alloc_batch 132
>         nr_inactive_anon 108
>         nr_active_anon 165006
>         nr_inactive_file 212275
>         nr_active_file 168709
>         nr_unevictable 64
>         nr_mlock 64
>         nr_anon_pages 164982
>         nr_mapped 90366
>         nr_file_pages 381184:
>         :
>         unevictable_pgs_mlocked 0
>         unevictable_pgs_munlocked 0
>         unevictable_pgs_cleared 0
>         unevictable_pgs_stranded 0
>         unevictable_pgs_mlockfreed 0
>         Copy to clipboard

有关此文件中可用参数的更多信息，请参阅 [Linux manual page](https://man7.org/linux/man-pages/man8/vmstat.8.html)。

### /proc/iomem

此文件显示系统各种设备驱动程序的内存映射。

- 要查看此文件的内容，可运行以下命令：

> 
> 
> cat /proc/iomem
>         Copy to clipboard
> 
> 
> **示例输出：**
> 
> 
> 007781b8-007791b7 : vmpm
>         010aa000-010abfff : tsens_physical
>         010ac000-010ac003 : pshold-base
>         010ad000-010aefff : tsens_physical
>         01680000-0168ffff : /soc/arm,smmu-anoc1@1680000
>         016c0000-016fffff : /soc/arm,smmu-anoc2@16c0000
>         01d0101c-01d0101f : sp2soc_irq_status
>         01d01024-01d01027 : sp2soc_irq_clr
>         01d01028-01d0102b : sp2soc_irq_mask
>         .
>         .
>         .
>         0caa0000-0caa3fff : jpeg_hw
>         0caa4000-0caa47ff : fd_core
>         0caa5000-0caa53ff : fd_misc
>         0cd00000-0cd3ffff : /soc/arm,smmu-mmss@cd00000
>         17817000-17817fff : msm-watchdog
>         17900000-1790dfff : msm-gladiator-erp
>         80000000-857fffff : System RAM
>         80080000-817fffff : Kernel code
>         82330000-82945fff : Kernel data
>         88f00000-8aafffff : System RAM
>         95300000-17e3bffff : System RAM
>         Copy to clipboard

### /proc/vmallocinfo

该文件通过 `vmalloc` 或 `ioremap` 显示了有关虚拟地址分配的详细信息。

- 要查看此文件的内容，可运行以下命令：

> 
> 
> cat /proc/vmallocinfo
>         Copy to clipboard
> 
> 
> **示例输出：**
> 
> 
> 0xbf000000-0xbf002000     8192            module\_alloc\_update\_bounds+0xc/0x5c     pages=1 vmalloc
> 0xbf004000-0xbf008000     16384          module\_alloc\_update\_bounds+0xc/0x5c     pages=3 vmalloc
> 0xee800000-0xef800000    16777216   iotable\_init+0x0/0xb0   phys=36800000   ioremap
> 0xf0000000-0xf0002000     8192            of\_iomap+0x30/0x38   ioremap
> 0xf0002000-0xf0004000     8192            of\_iomap+0x30/0x38   ioremap
> 0xf0004000-0xf000c000     32768          gen\_pool\_add\_virt+0x48/0xb8   pages= 7    vmalloc
> 0xf000c000-0xf000e000     8192            msm\_pm\_setup\_saved\_state+0xcc/0x1bc   ioremap
> ………………………
> 0xf0174000-0xf0176000    8192            msm\_cpu\_status\_probe+0xd8/0x20c   ioremap
> 0xf0f24000-0xf0f28000      16384         \_kgsl\_sharedmem\_page\_alloc+0xa0/0x41c   pages=3   vmalloc
> 0xf0f39000-0xf0f3e000      20480         \_kgsl\_sharedmem\_page\_alloc+0xa0/0x41c   pages=4   vmalloc
> 0xf0f61000-0xf0f66000      20480         \_kgsl\_sharedmem\_page\_alloc+0xa0/0x41c   pages=4   vmalloc
> ……….
> 0xfa400000-0xfa600000    2097152     iotable\_init+0x0/0xb0 phys=fa00000    ioremap
> 0xfa71e000-0xfa71f000     4096            iotable\_init+0x0/0xb0 phys=f991e000     ioremap
> 0xfefd8000-0xff000000     163840        pcpu\_get\_vm\_areas+0x0/0x56c  vmalloc

## memblock 接口

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

### /sys/kernel/debug/memblock/memory

该文件提供有关 Linux 内核可见的所有可用内存区域（HLOS 和 non-HLOS）的信息。要确定内核可访问的总内存，需计算每个区域起始地址与结束地址之间的差值，并将这些值求和以获取占用的总 RAM。剩余内存（即设备的 RAM 大小与已占用 RAM 之间的差异）为 non-HLOS 内存或其他子系统所占用的内存。

- 要查看此文件的内容，可运行以下命令：

> 
> 
> cat /sys/kernel/debug/memblock/memory
>         Copy to clipboard
> 
> 
> **示例输出：**
> 
> 
> 0: 0x0000000080000000..0x00000000857fffff
> 
> 
> 1: 0x0000000088f00000..0x000000008aafffff
> 
> 
> 2: 0x0000000095300000..0x000000017e3bffff

### /sys/kernel/debug/memblock/reserved

该文件提供有关系统中所有保留内存区域的信息。

- 要查看此文件的内容，可运行以下命令：

> 
> 
> cat /sys/kernel/debug/memblock/reserved
>         Copy to clipboard
> 
> 
> **示例输出：**
> 
> 
> 0: 0x0000000080080000..0x0000000082944fff
> 
> 
> 1: 0x0000000083200000..0x0000000083259bb4
> 
> 
> 2: 0x0000000083400000..0x00000000839506c9
> 
> 
> 3: 0x00000000f5800000..0x00000000ffbfffff
> 
> 
> 4: 0x00000000ffff7000..0x00000000ffffefff
> 
> 
> 5: 0x00000000ffffff40..0x00000000ffffff77
> 
> 
> 6: 0x00000000ffffff80..0x00000000ffffffb7
> 
> 
> 7: 0x00000000ffffffc0..0x00000000fffffff7
> 
> 
> 8: 0x0000000179258000..0x000000017d9fffff
> 
> 
> 9: 0x000000017da17000..0x000000017da1ffff
> 
> 
> 10: 0x000000017da20e00..0x000000017da26fff
> 
> 
> 11: 0x000000017da27300..0x000000017da2735f
> 
> 
> 12: 0x000000017da27380..0x000000017da273df
> 
> 
> 13: 0x000000017da27400..0x000000017da2755f
> 
> 
> 14: 0x000000017da27580..0x000000017da27587
> 
> 
> 15: 0x000000017da275c0..0x000000017da275c7
> 
> 
> 16: 0x000000017da29600..0x000000017da29924
> 
> 
> 17: 0x000000017da29940..0x000000017da29c64
> 
> 
> 18: 0x000000017da29c80..0x000000017da29fa4
> 
> 
> 19: 0x000000017da29fac..0x000000017da2a3f8
> 
> 
> 20: 0x000000017da2a3fc..0x000000017da2a42e
> 
> 
> 21: 0x000000017da2a430..0x000000017da2a45e
> 
> 
> 22: 0x000000017da2a460..0x000000017e3bffff

## 调试内存泄漏问题

要调试内核内存泄漏问题，请启用以下配置选项：

- `CONFIG_DEBUG_KMEMLEAK=y`
- `CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE=4000`
- `CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y`

默认情况下，内核线程每 10 分钟扫描一次内存并打印发现的新未引用对象的数量。例如，

unreferenced object 0xec26f000 (size 4096):

comm "Binder\_2", pid 4592, jiffies 8848 (age 336.710s)

hex dump (first 32 bytes):

ec 4d f8 c0 02 00 00 00 00 00 00 00 00 00 00 00 .M..............

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

backtrace:

[&lt;c0126f70&gt;] kmem\_cache\_alloc\_trace+0x17c/0x238

[&lt;c03059c4&gt;] ddl\_client\_transact+0xd0/0x158

[&lt;c0314a3c&gt;] ddl\_open+0x4c/0x194

[&lt;c0302288&gt;] vcd\_init\_client\_context+0x14/0x9c

[&lt;c02ffd10&gt;] vcd\_open\_in\_ready+0x3c/0x94

[&lt;c02fd31c&gt;] vcd\_open+0x214/0x274

[&lt;c031b244&gt;] vid\_dec\_open\_client+0x1d0/0x288

[&lt;c031b3ac&gt;] vid\_dec\_open+0x30/0x7c

[&lt;c012ff70&gt;] chrdev\_open+0x10c/0x134

[&lt;c012aa7c&gt;] \_\_dentry\_open.isra.12+0x190/0x29c

[&lt;c0138a78&gt;] do\_last.isra.29+0x690/0x6c0

[&lt;c0138c70&gt;] path\_openat+0xb8/0x35c

[&lt;c0138ff4&gt;] do\_filp\_open+0x2c/0x78

[&lt;c012b7a0&gt;] do\_sys\_open+0xd8/0x170

[&lt;c000df20&gt;] ret\_fast\_syscall+0x0/0x30

[&lt;ffffffff&gt;] 0xffffffff

通过在内核命令行中传递 `KMEMLEAK=off`，在启动时禁用 `KMEMLEAK` 选项。

有关 `kmemleak.txt` 文件的更多信息，请参阅[内核文档](https://www.kernel.org/doc/Documentation)。

以下额外内核配置选项可用于跟踪每个内存页的分配器：

- `CONFIG_PAGE_OWNER`
- `CONFIG_PAGE_OWNER_ENABLE_DEFAULT`
- `CONFIG_PAGE_EXTENSION`

启用这些选项有助于识别可能表明内存泄漏问题的多个分配操作。

## 识别内存损坏问题

启用以下内核配置选项以识别内存损坏问题：

- `CONFIG_PAGE_POISONING`
- `CONFIG_SLUB_DEBUG_ON`
- `CONFIG_DEBUG_LIST`
- `CONFIG_SLUB_DEBUG`

**示例日志：**

BUG &lt;slab cache affected&gt;: &lt;What went wrong&gt;

-----------------------------------------------

INFO: &lt;corruption start&gt;-&lt;corruption\_end&gt; &lt;more info&gt;

INFO: Slab &lt;address&gt; &lt;slab information&gt;

INFO: Object &lt;address&gt; &lt;object information&gt;

INFO: Allocated in &lt;kernel function&gt; age=&lt;jiffies since alloc&gt; cpu=&lt;allocated by cpu&gt; pid=&lt;pid of the process&gt;

INFO: Freed in &lt;kernel function&gt; age=&lt;jiffies since free&gt; cpu=&lt;freed by cpu&gt; pid=&lt;pid of the process&gt;

有关 slub 调试的更多信息，请参阅[内核文档](https://www.kernel.org/doc/Documentation)中的 `Documentation/vm/slub.txt`。

### 内存不足

当系统无法分配页面时，内核日志会显示类似以下的消息：

&lt;4&gt;[12146.861355] Thread-430: page allocation failure: order:0, mode:0x10d2

&lt;CALL STACK&gt;

&lt;4&gt;[12146.951687] Mem-info:

&lt;4&gt;[12146.953909] Normal per-cpu:

&lt;4&gt;[12146.956686] CPU 0: hi: 186, btch: 31 usd: 61

&lt;4&gt;[12146.961489] CPU 1: hi: 186, btch: 31 usd: 0

&lt;4&gt;[12146.966235] HighMem per-cpu:

&lt;4&gt;[12146.969122] CPU 0: hi: 186, btch: 31 usd: 54

&lt;4&gt;[12146.973877] CPU 1: hi: 186, btch: 31 usd: 0

…….

&lt;4&gt;[12147.010770] Normal free:53192kB min:3508kB low:4384kB high:5260kB ……..

&lt;4&gt;[12147.050805] lowmem\_reserve[]: 0 9022 9022

&lt;4&gt;[12147.054610] HighMem free:153360kB min:512kB low:1824kB high:3140kB ………

&lt;4&gt;[12147.095453] lowmem\_reserve[]: 0 0 0

&lt;4&gt;[12147.098617] Normal: 118\*4kB  232\*8kB 161\*16kB 110\*32kB 34\*64kB 9\*128kB 10\*256kB 6\*512kB  7\*1024kB  6\*2048kB 4\*4096kB  = 53224kB

&lt;4&gt;[12147.115455] HighMem: 2774\*4kB 11769\*8kB  3005\*16kB  1\*32kB  0\*64kB 0\*128kB 0\*256kB 0\*512kB 0\*1024kB 0\*2048kB 0\*4096kB = 153360kB

………………

这些消息表明系统无法分配请求的页面。日志消息中的最上面一行提供了有关内存不足问题的几个详细信息。例如，在以下日志中：

&lt;4&gt;[1214.855361] Thread-4: page allocation failure: order:2, mode:0x10d2

- **order**：表示页面的大小。在此示例中，2^2^ x PAGE\_SIZE (4 K) = 16 K

    - Linux 使用伙伴分配器以 2 的幂分配页面。

        - 伙伴分配器的最大大小为 10 阶，即 10 = 2^10^ x 4 kB = 4 MB。
        - 对于 &gt; 4 MB 的分配，使用替代分配法，例如连续内存分配器 (CMA)
    - 关于高阶分配失败，请检查内存是否可以虚拟连续，而不是物理连续。
- **mode**：表示所请求页面的类型

    - `mode` 提供关于获取免费页面 (GFP) 标志的信息。在此示例中，`mode` 为 `0x10d2`。
    - `mode` 是分配中所有 GFP 标志的“或”运算的结果。
- 系统中可用的页面

    页面分配失败消息打印关于系统中可用页面大小的详细信息。

Normal: 118\*4kB 232\*8kB 161\*16kB 110\*32kB 34\*64kB 9\*128kB   10\*256kB  6\*512kB 7\*1024kB 6\*2048kB 4\*4096kB = 53224kB

HighMem: 2774\*4kB 11769\*8kB 3005\*16kB 1\*32kB 0\*64kB 0\*128kB 0\*256kB 0\*512kB 0\*1024kB 0\*2048kB 0\*4096kB = 153360kB

### IOMMU 页面故障

输入-输出内存管理单元 (IOMMU) 也称为系统内存管理单元 (SMMU)，代表没有自己的 MMU 的子系统执行内存管理功能。

IOMMU 硬件模块允许物理上不连续的页面支持虚拟上连续的内存。IOMMU 中的内存转换逻辑与 CPU MMU 中的逻辑相同。

IOMMU 页面故障是最常见的 IOMMU 问题。当所请求的页面已在页表中映射但在内存中未找到时，会发生故障。故障处理程序会接收 IOMMU 的上下文库实例，并 dump 此上下文的寄存器。

以下日志指示 IOMMU 页面故障。

[   47.228992] msm\_iommu\_v1: Unexpected IOMMU page fault!

[   47.233115] msm\_iommu\_v1: name = mdp\_iommu

[   47.237238] msm\_iommu\_v1: context = mdp\_0 (0)

[   47.241507] msm\_iommu\_v1: Interesting registers:

[   47.246149] msm\_iommu\_v1: FAR    = 0000000000000000

[   47.250970] msm\_iommu\_v1: PAR    = 0000000000000000

[   47.255834] msm\_iommu\_v1: FSR    = 00000002 [TF ]

[   47.260540] msm\_iommu\_v1: FSYNR0 = 000005a1    FSYNR1 = 00030005

[   47.266528] msm\_iommu\_v1: TTBR0  = 0000000071a28000

[   47.271370] msm\_iommu\_v1: TTBR1  = 0000000000000000

[   47.276248] msm\_iommu\_v1: SCTLR  = 00001043    ACTLR  = 70000000

[   47.282221] msm\_iommu\_v1: CBAR  = 00000000    CBFRSYNRA  = 00000000

[   47.288521] msm\_iommu\_v1: PRRR   = ff0a81a8    NMRR   = 40e040e0

[   47.294461] msm\_iommu\_v1: NOTE: Value actually unknown for CBAR

[   47.300394] msm\_iommu\_v1: NOTE: Value actually unknown for CBFRSYNRA

[   47.306717] msm\_iommu\_v1: Page table in DDR shows PA = 0

下表描述了日志消息中捕获的字段。

表：IOMMU 页面故障日志中的信息

| 项目 | 说明 |
| --- | --- |
| `name` | 导致故障的硬件块名称。 |
| `FAR` | 故障地址寄存器（FAR）指示发生故障的地址。 |
| `FSR` | 故障状态寄存器（FSR）指示如下：<br><br><br><br>> <br>> <br>> <ul class="simple"><br>> <li><p>转换故障 (TF)</p></li><br>> <li><p>访问权限故障 (APF)</p></li><br>> <li><p>停滞状态 (SS)</p></li><br>> </ul> |

FSR 是 IOMMU 调试中最重要的寄存器之一。该寄存器具有读/写-清除访问权限。对该寄存器的读操作会读取寄存器中的值，而写操作则会清除已写入数据中与 1 对应的位，与 0 对应的位保持不变。本流程可防止在写入寄存器以清除旧故障时无意中清除新故障。该寄存器中一些有用的位如下：

表：故障状态寄存器中的位

| 位 | 说明 |
| --- | --- |
| `[Bit 1]: TF` | 转换故障（无效页表项） |
| `[Bit 2]: AFF` | 访问故障 |
| `[Bit 3]: APF` | 权限错误（写入只读区域） |
| `[Bit 4]: TLBMF` | TLB 未命中故障 |
| `[Bit 5]: HTWDEEF` | 硬件表遍历解码错误外部故障 |
| `[Bit 6]: HTWSEEF` | 硬件表遍历从属错误外部故障 |
| `[Bit 7]: MHF` | TLB 中的多次命中 |
| `[Bit 16]: SL` | 二级故障（二级页表发生故障） |
| `[Bit 30]: SS` | 停滞状态 |
| `[Bit 31]: MULTI` | 多处故障 |

`TF`、`APF` 和 `SL` 标志表示正常操作，而 `TLBMF`、`HTWDEEF`、`HTWSEEF` 和 `MHF` 标志表示存在问题。

#### IOMMU 页表

IOMMU 页表 dump 提供了来自 FAR 和内核日志中寄存器 dump 的故障地址。此故障地址代表虚拟地址，您可以从页表中获取相应的物理地址。从页表 dump 中，您可以确定请求的地址是否已映射。每个 IOMMU 域都有一个页表，dump 包含每个域的页表。当前共有六个域。

以下是 `Domain: 2` 页表的示例 dump。

Domain: 2 [L2 cache redirect for page tables is OFF]

0x00000000--0x0001ffff   [0x00020000]  [UNMAPPED]

0x00020000--0x01807fff   [0x017e8000]  A:0x82a8e000--0x84275fff [0x017e8000] [R/W][4K]

0x01808000--0x01939fff   [0x00132000]  A:0xf0c24000--0xf0d55fff [0x00132000] [R/W][4K]

0x0193a000--0x0199ffff   [0x00066000]  A:0xf13fa000--0xf145ffff [0x00066000] [R/W][4K]

0x019a0000--0x01e85fff   [0x004e6000]  A:0xf966e000--0xf9b53fff [0x004e6000] [R/W][4K]

0x01e86000--0x01ffffff   [0x0017a000]  [UNMAPPED]

0x02000000--0x02feffff   [0x00ff0000]  A:0xf5a22000--0xf6a11fff [0x00ff0000] [R/W][4K]

在本示例中，第一列表示虚拟地址，第二列表示连续物理地址相应区域的字节数，第三列表示物理地址。此外还提到了每个区域的权限。

### 内存映射

有关内存映射的更多信息，请参阅[发布说明](https://docs.qualcomm.com/bundle/resource/topics/80-70029-300/introduction.html)。

### 堆栈损坏

错误的编码逻辑访问堆栈中的内存位置，会导致这些内存位置的值发生变化，从而引发堆栈损坏。堆栈损坏可以下列方式发生：

- 由于错误的代码逻辑，程序会消耗所有堆栈内存，并且将内存写入堆栈边界之外，从而导致堆栈溢出。
- 访问超出边界的数组。
- 指向堆栈地址的未定义或已释放的指针。
- 调用者函数的返回地址已损坏。

要识别堆栈损坏问题，启用以下内核配置选项：

- `CONFIG_STACKPROTECTOR`
- `CONFIG_STACKPROTECTOR_STRONG`

内核地址清理器 (KASAN) 工具还有助于识别某些堆栈损坏问题。

Last Published: Apr 15, 2026

[Previous Topic
配置内核进行调试](https://docs.qualcomm.com/bundle/publicresource/80-70029-12SC/topics/configure_the_kernel_for_debugging.md) [Next Topic
跟踪内核函数](https://docs.qualcomm.com/bundle/publicresource/80-70029-12SC/topics/trace_kernel_functions.md)