操作系统番外2(Linux的虚拟内存)(TODO)
在 Linux 中虚拟内存不仅仅是地址转换它是一套复杂的资源管理机制。以下是作为 BSP 工程师最需要掌握的核心概念和调试手段。1. Linux 虚拟内存布局 (Memory Layout)Linux 将虚拟地址空间划分为两大部分用户空间 (User Space)和内核空间 (Kernel Space)。用户空间每个进程都有独立的 $2^{N}$ 虚拟空间32位系统为 3GB64位系统巨大。内核空间所有进程共享同一个内核映射。Lowmem (直接映射区)物理内存的前一部分直接线性映射到内核虚拟地址。Vmalloc 区用于非连续物理内存的映射适合分配大块缓冲区。2. 核心机制从“静态映射”到“动态按需”你在裸机中可能是预先写死页表而 Linux 是“按需分页” (Paging on demand)页表 (Page Tables)Linux 使用多级页表如 ARM64 通常是 4 级PGD - PUD - PMD - PTE。缺页异常 (Page Fault)当你访问一个尚未建立映射的虚拟地址时内核会触发缺页异常在异常处理函数中实时分配物理页并填充页表。3. BSP 工程师必看的内存节点在调试 Camera 数据流或大块 DMA 缓冲区时你需要通过以下节点监控内存状态。/proc/meminfo(全局视角)用途查看系统总内存使用情况。关键指标MemTotal: 总物理内存。MemAvailable: 真正可用的内存比Free更准确因为它计入了可回收的 Cache。AnonPages: 进程使用的匿名内存堆、栈。/proc# cat /proc/meminfoShmemPmdMapped: 0 kBFileHugePages: 0 kBFilePmdMapped: 0 kBCmaTotal: 0 kBCmaFree: 0 kBUnaccepted: 0 kBHugePages_Total: 0HugePages_Free: 0HugePages_Rsvd: 0HugePages_Surp: 0Hugepagesize: 2048 kBHugetlb: 0 kBDirectMap4k: 66332 kBDirectMap2M: 5173248 kBDirectMap1G: 10485760 kB/proc/[pid]/mapssmaps(进程视角)用途查看某个具体进程如你的 AI 视觉处理进程的内存映射。实战通过cat /proc/self/maps可以看到代码段、数据段、堆以及共享库.so分别映射在什么虚拟地址。/proc# cat 10143/maps59865aa00000-59865aa19000 r--p 00000000 07:00 1049563 /usr/bin/tmux59865aa19000-59865aab0000 r-xp 00019000 07:00 1049563 /usr/bin/tmux/lib/x86_64-linux-gnu/libevent_core-2.1.so.7.0.17d00df3d7000-7d00df3e5000 r--p 00000000 07:00 5112886 /usr/lib/x86_64-linux-gnu/libtinfo.so.6.37d00df3e5000-7d00df3f6000 r-xp 0000e000 07:00 5112886 /usr/lib/x86_64-linux-gnu/libtinfo.so.6.37d00df3f6000-7d00df404000 r--p 0001f000 07:00 5112886 /usr/lib/x86_64-linux-gnu/libtinfo.so.6.37d00df404000-7d00df408000 r--p 0002c000 07:00 5112886 /usr/lib/x86_64-linux-gnu/libtinfo.so.6.37d00df408000-7d00df409000 rw-p 00030000 07:00 5112886 /usr/lib/x86_64-linux-gnu/libtinfo.so.6.37d00df409000-7d00df40a000 r--p 00000000 07:00 1079497 /usr/lib/x86_64-linux-gnu/libutempter.so.1.2.17d00df40a000-7d00df40b000 r-xp 00001000 07:00 1079497 /usr/lib/x86_64-linux-gnu/libutempter.so.1.2.17d00df40b000-7d00df40c000 r--p 00002000 07:00 1079497 /us/lib/x86_64-linux-gnu/ld-linux-x86-64.so.27d00df44a000-7d00df455000 r--p 0002c000 07:00 5112750 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.27d00df456000-7d00df458000 r--p 00037000 07:00 5112750 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.27d00df458000-7d00df45a000 rw-p 00039000 07:00 5112750 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.27ffc9b7c1000-7ffc9b7e2000 rw-p 00000000 00:00 0 [stack]7ffc9b7ec000-7ffc9b7f0000 r--p 00000000 00:00 0 [vvar]7ffc9b7f0000-7ffc9b7f2000 r-xp 00000000 00:00 0 [vdso]ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]/proc/buddyinfo(物理内存碎片)用途查看内核伙伴系统Buddy System的空闲页分布。排查逻辑如果你在 Bring-up 驱动时发现kmalloc分配大块内存失败即使总内存够用看这里也能发现是否是因为内存碎片严重高 order 的空闲块为 0。4. 驱动开发中的关键接口你在做 BSP 调试时经常会用到这几个函数它们是操作虚拟内存的“抓手”ioremap()场景将硬件寄存器的物理地址PA映射到内核虚拟地址VA以便 CPU 读写寄存器。mmap()(用户态)场景将设备内存如 Camera Buffer直接映射到用户空间实现零拷贝 (Zero-copy)。dma_alloc_coherent()场景分配物理连续且关闭 Cache 的内存用于 DMA 传输。我将 Linux 页大小从 4KB 改为 2MB结果性能彻底翻车了Linux分页机制之分页机制的实现详解--Linux内存管理(八) - yooooooo - 博客园