Linux --- 内存管理内核子系统

Linux内存管理(Memory Management,简称MM)是一套庞大、分层协作的内核子系统,统一负责虚拟地址空间、页表、缺页异常、内存分配、页面回收、Swap、Page Cache、OOM等全部内存相关逻辑。决定进程可访问的地址范围、虚拟地址映射到哪个物理页、物理内存如何分配,内存压力时如何回收页面,回答「内存在哪里、归谁、是否驻留内存」。

一、内存管理整体分层链路

以一行简单C++动态内存分配代码auto* p = new char[1024];为例,内存分配链路是用户态分配器 → Linux内核MM子系统 → 物理内存硬件三层架构。

需要注意,一次具体的new/malloc并不一定进入内核:如果用户态分配器能够从tcache、Arena等已有空闲内存中满足请求,则不会触发brk/mmap系统调用。

ptmalloc 在用户态预先缓存大块内存,应用调用 malloc 时优先从缓存拿,不够才向内核brk/mmap申请内存;free 不会直接还给内核,放回缓存供后续复用
#mermaid-svg-rk9lKLHe6H97V2L1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rk9lKLHe6H97V2L1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rk9lKLHe6H97V2L1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rk9lKLHe6H97V2L1 .error-icon{fill:#552222;}#mermaid-svg-rk9lKLHe6H97V2L1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rk9lKLHe6H97V2L1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rk9lKLHe6H97V2L1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rk9lKLHe6H97V2L1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rk9lKLHe6H97V2L1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rk9lKLHe6H97V2L1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rk9lKLHe6H97V2L1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rk9lKLHe6H97V2L1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rk9lKLHe6H97V2L1 .marker.cross{stroke:#333333;}#mermaid-svg-rk9lKLHe6H97V2L1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rk9lKLHe6H97V2L1 p{margin:0;}#mermaid-svg-rk9lKLHe6H97V2L1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rk9lKLHe6H97V2L1 .cluster-label text{fill:#333;}#mermaid-svg-rk9lKLHe6H97V2L1 .cluster-label span{color:#333;}#mermaid-svg-rk9lKLHe6H97V2L1 .cluster-label span p{background-color:transparent;}#mermaid-svg-rk9lKLHe6H97V2L1 .label text,#mermaid-svg-rk9lKLHe6H97V2L1 span{fill:#333;color:#333;}#mermaid-svg-rk9lKLHe6H97V2L1 .node rect,#mermaid-svg-rk9lKLHe6H97V2L1 .node circle,#mermaid-svg-rk9lKLHe6H97V2L1 .node ellipse,#mermaid-svg-rk9lKLHe6H97V2L1 .node polygon,#mermaid-svg-rk9lKLHe6H97V2L1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rk9lKLHe6H97V2L1 .rough-node .label text,#mermaid-svg-rk9lKLHe6H97V2L1 .node .label text,#mermaid-svg-rk9lKLHe6H97V2L1 .image-shape .label,#mermaid-svg-rk9lKLHe6H97V2L1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-rk9lKLHe6H97V2L1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rk9lKLHe6H97V2L1 .rough-node .label,#mermaid-svg-rk9lKLHe6H97V2L1 .node .label,#mermaid-svg-rk9lKLHe6H97V2L1 .image-shape .label,#mermaid-svg-rk9lKLHe6H97V2L1 .icon-shape .label{text-align:center;}#mermaid-svg-rk9lKLHe6H97V2L1 .node.clickable{cursor:pointer;}#mermaid-svg-rk9lKLHe6H97V2L1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rk9lKLHe6H97V2L1 .arrowheadPath{fill:#333333;}#mermaid-svg-rk9lKLHe6H97V2L1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rk9lKLHe6H97V2L1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rk9lKLHe6H97V2L1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rk9lKLHe6H97V2L1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rk9lKLHe6H97V2L1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rk9lKLHe6H97V2L1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rk9lKLHe6H97V2L1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rk9lKLHe6H97V2L1 .cluster text{fill:#333;}#mermaid-svg-rk9lKLHe6H97V2L1 .cluster span{color:#333;}#mermaid-svg-rk9lKLHe6H97V2L1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rk9lKLHe6H97V2L1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rk9lKLHe6H97V2L1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-rk9lKLHe6H97V2L1 .icon-shape,#mermaid-svg-rk9lKLHe6H97V2L1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rk9lKLHe6H97V2L1 .icon-shape p,#mermaid-svg-rk9lKLHe6H97V2L1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rk9lKLHe6H97V2L1 .icon-shape .label rect,#mermaid-svg-rk9lKLHe6H97V2L1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rk9lKLHe6H97V2L1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rk9lKLHe6H97V2L1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rk9lKLHe6H97V2L1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-rk9lKLHe6H97V2L1 .app>*{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .app span{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .app tspan{fill:#0d47a1!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .runtime>*{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .runtime span{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .runtime tspan{fill:#1b5e20!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .user>*{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .user span{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .user tspan{fill:#e65100!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .kernel>*{fill:#f3e5f5!important;stroke:#8e24aa!important;stroke-width:1.5px!important;color:#4a148c!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .kernel span{fill:#f3e5f5!important;stroke:#8e24aa!important;stroke-width:1.5px!important;color:#4a148c!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .kernel tspan{fill:#4a148c!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .phys>*{fill:#e0f7fa!important;stroke:#00acc1!important;stroke-width:1.5px!important;color:#006064!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .phys span{fill:#e0f7fa!important;stroke:#00acc1!important;stroke-width:1.5px!important;color:#006064!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .phys tspan{fill:#006064!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .ram>*{fill:#ffebee!important;stroke:#e53935!important;stroke-width:2px!important;color:#b71c1c!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .ram span{fill:#ffebee!important;stroke:#e53935!important;stroke-width:2px!important;color:#b71c1c!important;}#mermaid-svg-rk9lKLHe6H97V2L1 .ram tspan{fill:#b71c1c!important;} new / delete
malloc / free
brk / mmap 系统调用
C++ Application
C/C++ Runtime
Userspace Memory Allocator

glibc ptmalloc
tcache

线程本地缓存
arena

多线程独立分配域
bins / free chunk

空闲块链表
本地空闲内存耗尽
Linux Kernel Memory Management
mm_struct

进程地址空间描述符
VMA

虚拟内存区域
Page Table

多级页表
Page Fault

缺页异常处理
Page Allocator

物理页分配器
Page Reclaim

页面回收
Swap
Physical Memory
NUMA Node

NUMA 节点
Zone

内存域
PCP

Per-CPU Pageset
Buddy Allocator

伙伴系统
RAM

硬件侧地址转换链路:
#mermaid-svg-Cbg1GGc0ZEvKwCEk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .error-icon{fill:#552222;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .marker.cross{stroke:#333333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Cbg1GGc0ZEvKwCEk p{margin:0;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .cluster-label text{fill:#333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .cluster-label span{color:#333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .cluster-label span p{background-color:transparent;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .label text,#mermaid-svg-Cbg1GGc0ZEvKwCEk span{fill:#333;color:#333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .node rect,#mermaid-svg-Cbg1GGc0ZEvKwCEk .node circle,#mermaid-svg-Cbg1GGc0ZEvKwCEk .node ellipse,#mermaid-svg-Cbg1GGc0ZEvKwCEk .node polygon,#mermaid-svg-Cbg1GGc0ZEvKwCEk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .rough-node .label text,#mermaid-svg-Cbg1GGc0ZEvKwCEk .node .label text,#mermaid-svg-Cbg1GGc0ZEvKwCEk .image-shape .label,#mermaid-svg-Cbg1GGc0ZEvKwCEk .icon-shape .label{text-anchor:middle;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .rough-node .label,#mermaid-svg-Cbg1GGc0ZEvKwCEk .node .label,#mermaid-svg-Cbg1GGc0ZEvKwCEk .image-shape .label,#mermaid-svg-Cbg1GGc0ZEvKwCEk .icon-shape .label{text-align:center;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .node.clickable{cursor:pointer;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .arrowheadPath{fill:#333333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Cbg1GGc0ZEvKwCEk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Cbg1GGc0ZEvKwCEk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Cbg1GGc0ZEvKwCEk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .cluster text{fill:#333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .cluster span{color:#333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Cbg1GGc0ZEvKwCEk rect.text{fill:none;stroke-width:0;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .icon-shape,#mermaid-svg-Cbg1GGc0ZEvKwCEk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .icon-shape p,#mermaid-svg-Cbg1GGc0ZEvKwCEk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .icon-shape .label rect,#mermaid-svg-Cbg1GGc0ZEvKwCEk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Cbg1GGc0ZEvKwCEk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Cbg1GGc0ZEvKwCEk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .addr>*{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .addr span{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .addr tspan{fill:#0d47a1!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .hw>*{fill:#f3e5f5!important;stroke:#8e24aa!important;stroke-width:1.5px!important;color:#4a148c!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .hw span{fill:#f3e5f5!important;stroke:#8e24aa!important;stroke-width:1.5px!important;color:#4a148c!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .hw tspan{fill:#4a148c!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .hit>*{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .hit span{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .hit tspan{fill:#1b5e20!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .miss>*{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .miss span{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .miss tspan{fill:#e65100!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .out>*{fill:#ffebee!important;stroke:#e53935!important;stroke-width:2px!important;color:#b71c1c!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .out span{fill:#ffebee!important;stroke:#e53935!important;stroke-width:2px!important;color:#b71c1c!important;}#mermaid-svg-Cbg1GGc0ZEvKwCEk .out tspan{fill:#b71c1c!important;} Virtual Address

虚拟地址
MMU

内存管理单元(硬件)
TLB Hit

TLB 命中
TLB Miss

TLB 未命中
Physical Address

物理地址
Page Walk

硬件遍历多级页表

三层体系总结:

  1. 用户态 :malloc/free,ptmalloc/tcache/arena;
  2. 内核态:Linux MM子系统,VMA、页表、缺页、页面分配与回收;
  3. 硬件:MMU、TLB、物理内存RAM。

注:业内所说Linux Memory Manager,特指内核内部MM子系统,不含glibc用户态分配器。

二、进程虚拟地址空间

2.1 Virtual Address Space

Linux不允许进程直接操作物理地址,每个进程都拥有独立的虚拟地址空间。64位进程典型虚拟地址布局:

虚拟内存价值:

  1. 进程地址空间隔离,一个进程无法直接访问另一进程内存;
  2. 屏蔽复杂物理内存拓扑(NUMA、内存空洞);
  3. 支持按需分页(Demand Paging);
  4. 支持进程间共享内存、文件映射;
  5. 实现虚拟连续,物理可不连续。

2.2 mm_struct 进程地址空间描述符

内核使用struct mm_struct描述一个进程完整虚拟地址空间,是进程内存顶层管理对象。
#mermaid-svg-601A21f0BFTjRuhW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-601A21f0BFTjRuhW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-601A21f0BFTjRuhW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-601A21f0BFTjRuhW .error-icon{fill:#552222;}#mermaid-svg-601A21f0BFTjRuhW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-601A21f0BFTjRuhW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-601A21f0BFTjRuhW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-601A21f0BFTjRuhW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-601A21f0BFTjRuhW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-601A21f0BFTjRuhW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-601A21f0BFTjRuhW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-601A21f0BFTjRuhW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-601A21f0BFTjRuhW .marker.cross{stroke:#333333;}#mermaid-svg-601A21f0BFTjRuhW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-601A21f0BFTjRuhW p{margin:0;}#mermaid-svg-601A21f0BFTjRuhW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-601A21f0BFTjRuhW .cluster-label text{fill:#333;}#mermaid-svg-601A21f0BFTjRuhW .cluster-label span{color:#333;}#mermaid-svg-601A21f0BFTjRuhW .cluster-label span p{background-color:transparent;}#mermaid-svg-601A21f0BFTjRuhW .label text,#mermaid-svg-601A21f0BFTjRuhW span{fill:#333;color:#333;}#mermaid-svg-601A21f0BFTjRuhW .node rect,#mermaid-svg-601A21f0BFTjRuhW .node circle,#mermaid-svg-601A21f0BFTjRuhW .node ellipse,#mermaid-svg-601A21f0BFTjRuhW .node polygon,#mermaid-svg-601A21f0BFTjRuhW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-601A21f0BFTjRuhW .rough-node .label text,#mermaid-svg-601A21f0BFTjRuhW .node .label text,#mermaid-svg-601A21f0BFTjRuhW .image-shape .label,#mermaid-svg-601A21f0BFTjRuhW .icon-shape .label{text-anchor:middle;}#mermaid-svg-601A21f0BFTjRuhW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-601A21f0BFTjRuhW .rough-node .label,#mermaid-svg-601A21f0BFTjRuhW .node .label,#mermaid-svg-601A21f0BFTjRuhW .image-shape .label,#mermaid-svg-601A21f0BFTjRuhW .icon-shape .label{text-align:center;}#mermaid-svg-601A21f0BFTjRuhW .node.clickable{cursor:pointer;}#mermaid-svg-601A21f0BFTjRuhW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-601A21f0BFTjRuhW .arrowheadPath{fill:#333333;}#mermaid-svg-601A21f0BFTjRuhW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-601A21f0BFTjRuhW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-601A21f0BFTjRuhW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-601A21f0BFTjRuhW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-601A21f0BFTjRuhW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-601A21f0BFTjRuhW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-601A21f0BFTjRuhW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-601A21f0BFTjRuhW .cluster text{fill:#333;}#mermaid-svg-601A21f0BFTjRuhW .cluster span{color:#333;}#mermaid-svg-601A21f0BFTjRuhW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-601A21f0BFTjRuhW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-601A21f0BFTjRuhW rect.text{fill:none;stroke-width:0;}#mermaid-svg-601A21f0BFTjRuhW .icon-shape,#mermaid-svg-601A21f0BFTjRuhW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-601A21f0BFTjRuhW .icon-shape p,#mermaid-svg-601A21f0BFTjRuhW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-601A21f0BFTjRuhW .icon-shape .label rect,#mermaid-svg-601A21f0BFTjRuhW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-601A21f0BFTjRuhW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-601A21f0BFTjRuhW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-601A21f0BFTjRuhW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-601A21f0BFTjRuhW .proc>*{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-601A21f0BFTjRuhW .proc span{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-601A21f0BFTjRuhW .proc tspan{fill:#0d47a1!important;}#mermaid-svg-601A21f0BFTjRuhW .core>*{fill:#f3e5f5!important;stroke:#8e24aa!important;stroke-width:2px!important;color:#4a148c!important;}#mermaid-svg-601A21f0BFTjRuhW .core span{fill:#f3e5f5!important;stroke:#8e24aa!important;stroke-width:2px!important;color:#4a148c!important;}#mermaid-svg-601A21f0BFTjRuhW .core tspan{fill:#4a148c!important;}#mermaid-svg-601A21f0BFTjRuhW .vma>*{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-601A21f0BFTjRuhW .vma span{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-601A21f0BFTjRuhW .vma tspan{fill:#e65100!important;}#mermaid-svg-601A21f0BFTjRuhW .pt>*{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-601A21f0BFTjRuhW .pt span{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-601A21f0BFTjRuhW .pt tspan{fill:#1b5e20!important;}#mermaid-svg-601A21f0BFTjRuhW .etc>*{fill:#eceff1!important;stroke:#607d8b!important;stroke-width:1.5px!important;color:#263238!important;}#mermaid-svg-601A21f0BFTjRuhW .etc span{fill:#eceff1!important;stroke:#607d8b!important;stroke-width:1.5px!important;color:#263238!important;}#mermaid-svg-601A21f0BFTjRuhW .etc tspan{fill:#263238!important;} Process

进程
mm_struct

进程地址空间描述符
VMA

代码段
VMA

数据段
VMA

堆
VMA

栈
VMA

mmap 映射区
Page Tables

多级页表
...

同一进程内所有线程共享同一个mm_struct,这就是同进程线程可以直接访问对方堆、全局变量的根本原因。

线程栈属于虚拟地址空间,但每个线程拥有独立栈VMA。

2.3 VMA(vm_area_struct)

内核使用VMA(Virtual Memory Area,struct vm_area_struct)描述一段连续且映射属性一致的虚拟地址区域 。这里的映射属性不仅包括读、写、执行权限,还包括文件映射关系、页保护属性以及其他VMA相关策略。

VMA描述进程中哪些虚拟地址范围是合法的,以及这些区域应具有怎样的映射属性和访问权限;

每段VMA记录vm_start、vm_end、vm_flags读写执行权限、vm_page_prot页保护属性、vm_file映射文件等信息。

text 复制代码
mm_struct
    │
    ├── VMA:text代码段
    ├── VMA:heap堆
    ├── VMA:shared library共享库
    ├── VMA:mmap文件映射
    └── VMA:stack栈

区分

  • mm_struct:整个进程虚拟地址空间的顶层容器;
  • vm_area_struct:一段连续、属性一致的虚拟地址区域。

三、虚拟地址到物理地址映射:页表、MMU、TLB

3.1 Page Table(多级页表)

页表保存地址转换所需的映射信息,供MMU完成VA→PA转换。正常的已映射内存访问通常不会查询VMA;当发生Page Fault等异常时,内核才会根据VMA判断该地址是否合法以及应如何建立或修复页表映射。

text 复制代码
PGD → P4D → PUD → PMD → PTE → Physical Page Frame

不同硬件架构不一定启用全部五级,不需要的层级会通过Page Table Folding折叠,简化为更少级数。

3.2 PTE(Page Table Entry)

PTE是页表最底层条目,虚拟地址被切分为多级索引 + 页内偏移 。

PTE中包含物理页帧号、Present位、读写权限、用户/内核态标记、Accessed访问位、Dirty脏位等元数据。

地址转换公式:

VA = 虚拟页基地址 + 页内Offset

PA = 物理页基地址 + 页内Offset

页表以Page为最小单位维护虚拟地址到物理页帧映射与访问权限。

3.3 MMU

MMU(Memory Management Unit)是CPU内部硬件单元,真正执行地址转换。普通内存访问不需要内核参与地址翻译,全部由CPU硬件完成。只有PTE标记无效、权限非法时,MMU触发异常,陷入内核处理Page Fault。

3.4 TLB(Translation Lookaside Buffer)

TLB(Translation Lookaside Buffer)是CPU内部用于加速地址转换的高速缓存,缓存近期使用过的虚拟页→物理页的地址转换结果以及相关权限属性,从而避免每次内存访问都执行多级页表遍历。
#mermaid-svg-Xj8Fcz8Fb9UfLc6w{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .error-icon{fill:#552222;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .marker.cross{stroke:#333333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w p{margin:0;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .cluster-label text{fill:#333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .cluster-label span{color:#333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .cluster-label span p{background-color:transparent;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .label text,#mermaid-svg-Xj8Fcz8Fb9UfLc6w span{fill:#333;color:#333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node rect,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node circle,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node ellipse,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node polygon,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .rough-node .label text,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node .label text,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .image-shape .label,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .icon-shape .label{text-anchor:middle;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .rough-node .label,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node .label,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .image-shape .label,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .icon-shape .label{text-align:center;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node.clickable{cursor:pointer;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .arrowheadPath{fill:#333333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .cluster text{fill:#333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .cluster span{color:#333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w rect.text{fill:none;stroke-width:0;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .icon-shape,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .icon-shape p,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .icon-shape .label rect,#mermaid-svg-Xj8Fcz8Fb9UfLc6w .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .addr>*{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .addr span{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .addr tspan{fill:#0d47a1!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .hw>*{fill:#f3e5f5!important;stroke:#8e24aa!important;stroke-width:1.5px!important;color:#4a148c!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .hw span{fill:#f3e5f5!important;stroke:#8e24aa!important;stroke-width:1.5px!important;color:#4a148c!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .hw tspan{fill:#4a148c!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .hit>*{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .hit span{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .hit tspan{fill:#1b5e20!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .miss>*{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .miss span{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .miss tspan{fill:#e65100!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .out>*{fill:#ffebee!important;stroke:#e53935!important;stroke-width:2px!important;color:#b71c1c!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .out span{fill:#ffebee!important;stroke:#e53935!important;stroke-width:2px!important;color:#b71c1c!important;}#mermaid-svg-Xj8Fcz8Fb9UfLc6w .out tspan{fill:#b71c1c!important;} Virtual Address

虚拟地址
TLB 查询
TLB Hit

TLB 命中
TLB Miss

TLB 未命中
Physical Address

物理地址
Page Walk

硬件遍历多级页表

三者关系:

  • Page Table :存储虚拟地址转换所需的页表条目;对于当前未驻留或尚未建立物理映射的虚拟页,对应叶子条目可能不存在或处于Non-Present状态;
  • TLB :CPU内部的地址转换缓存,保存近期使用的虚拟页→物理页转换结果及属性;
  • MMU:硬件执行地址翻译和权限检查;TLB Miss时根据架构执行Page Walk,遇到不存在的映射或权限冲突时触发Page Fault等异常。

四、缺页异常Page Fault与按需分页Demand Paging

4.1 申请虚拟内存不等于立即分配全部物理页

一个常见误区是认为调用malloc后,请求大小对应的物理RAM就一定立即完成分配。实际上需要区分两种情况:

  • 如果malloc能够直接复用用户态分配器中已有的空闲Chunk,这部分内存甚至不会进入内核;
  • 如果用户态分配器需要通过brk扩展堆 或通过匿名mmap申请新的虚拟地址空间,在Linux典型的Demand Paging机制下,通常不会立即为整个虚拟地址范围分配并驻留全部物理数据页,而是在后续实际访问页面时通过Page Fault逐步建立物理页映射。
cpp 复制代码
char* p = static_cast<char*>(malloc(100 * 1024 * 1024));

假设该大块请求最终由glibc通过匿名mmap向内核申请新的地址空间,那么此时主要建立的是虚拟地址映射关系;对应的数据页通常不会一次性全部驻留RAM,而是在后续实际访问时按需建立物理页映射。

4.2 第一次访问触发Page Fault

执行p[0] = 1;,CPU访问虚拟地址流程:

  1. CPU给出虚拟地址,MMU查询TLB,TLB Miss;
  2. 硬件遍历多级页表,发现PTE标记Not Present;
  3. MMU触发缺页异常,CPU陷入内核;
  4. 内核缺页处理函数,查找对应VMA,校验地址、访问权限合法性;
  5. 合法,则调用Page Allocator分配物理页,填充PTE建立映射;
  6. 返回用户态,重新执行触发异常的写指令。

4.3 完整访问链路示例

cpp 复制代码
char* p = static_cast<char*>(malloc(100 * 1024 * 1024));
p[50 * 1024 * 1024] = 1;

五、物理内存管理:NUMA、Zone、PCP、Buddy

5.1 Page / Folio

Linux内核以Page为基础单元管理物理内存。x86_64默认基础页大小4KB。

内核通过struct page/Folio等数据结构维护页面相关元数据,例如引用计数、映射计数、页面状态Flag、Dirty状态、LRU/Active状态、锁状态以及文件映射或匿名内存相关信息。页面可能被多个地址空间共享(共享内存),page不一定是只属于一个进程的。

Linux近年来引入struct folio作为更高层的内存管理抽象,一个Folio可以包含一个或多个连续基础Page。它主要用于避免大量代码反复处理Compound Page的head/tail语义,并逐步成为Page Cache、匿名内存等MM路径中的重要管理单位。Folio是建立在Page之上的、更适合管理一组相关页面的抽象。

5.2 NUMA Node (Non-Uniform Memory Access)非一致内存访问

多 CPU 服务器架构,不同 CPU 访问内存的速度不一样

NUMA :内存被切分成多块,本地内存访问快,跨节点访问远端内存慢

多Socket服务器存在NUMA非一致内存架构:不同CPU访问本地内存延迟低,跨节点远端内存访问延迟显著更高。

text 复制代码
CPU 0
 │
 └── NUMA Node 0
       └── RAM 0
CPU 1
 │
 └── NUMA Node 1
       └── RAM 1

内存分配时,内核需要选择分配节点,优先本地内存,减少远端访问延迟 ,对应内核numa_balancing自动页面迁移机制。

5.3 Zone内存域

单个NUMA Node内部,按硬件寻址限制划分Zone:ZONE_DMA、ZONE_DMA32、ZONE_NORMAL、ZONE_MOVABLE。

  • ZONE_DMA / ZONE_DMA32 :专门存放物理低地址内存,用于寻址能力受限的传统 DMA 外设 。ZONE_DMA 对应 ISA 设备(x86 下 0~16MB);ZONE_DMA32 供只能访问 32 位物理地址(4GB 以内)的 DMA 控制器。现代设备优先使用 DMA 映射 API,不再强制依赖这两个 zone。
  • ZONE_NORMAL :内核可直接线性映射的普通物理内存,既可以用于内核分配,也可用于用户态进程内存。64 位 x86 几乎全部内存都属于 ZONE_NORMAL。
  • ZONE_MOVABLE :逻辑内存域,只接收可迁移类型页面(用户匿名页、pagecache 等) ;核心目的是支持内存热插拔(内存下线),同时辅助内存压缩 (compaction),降低物理碎片、便于分配大连续页(巨页 THP/HugePage)。内核不可迁移分配(kmalloc、页表等)不会从该 zone 分配。

物理内存层级关系:

text 复制代码
Physical Memory
       │
       ▼
    NUMA Node
       │
       ▼
      Zone
       │
       ▼
      Page / Folio

5.4 Page Allocator分配路径

内核申请物理页入口alloc_pages(),分配优先级:

text 复制代码
Page Allocation
       │
       ▼
PCP Per-CPU Pageset
       │
       │PCP空闲页不足
       ▼
Buddy Allocator伙伴系统

5.5 PCP(Per-CPU Pageset)

多核场景,全局Buddy链表存在严重锁竞争。PCP为每个CPU维护本地页面缓存,单页分配优先从本CPUPCP取页,减少全局锁争抢。思想类似用户态tcache,本地缓存优先,不足再访问全局资源。

5.6 Buddy Allocator伙伴系统

负责连续物理页 分配与回收,分配单位2^order个连续Page。

一块 2k+12^{k+1}2k+1 大小的块对半分裂,得到两个 2k2^k2k 的子块,这一对就叫伙伴 (buddy) ;只有这一对伙伴同时空闲,才能合并回大块。

1. 基础数据结构

维护一组空闲链表数组 free_area \[\] ,数组下标叫 order:

  • free_area[order]:存放所有大小为2order2^{order}2order 个页的空闲连续块
  • order=0 → 20=12^0=120=1页(4KB)
  • order=1 → 21=22^1=221=2页(8KB)
  • order=n → 2n2^n2n页

块地址约束 :大小2k2^k2k的块,起始地址必须是2k2^k2k对齐。

伙伴地址计算公式 :块起始地址p,order=k,块大小S=2kS=2^kS=2k页:

buddy(p,k)={p+S(p mod 2S==0)p−S(p mod 2S==S)\text{buddy}(p,k)= \begin{cases} p+S & (p \bmod 2S ==0)\\ p-S & (p \bmod 2S ==S) \end{cases}buddy(p,k)={p+Sp−S(pmod2S==0)(pmod2S==S)

用位运算快速计算:buddy = p ^ (1 << k),这是 Linux 内核的写法。

2. 分配流程(allocate)

需求:申请n个连续页

  1. 向上取 order:找到最小的k,满足2k≥n2^k \ge n2k≥n
  2. 从free_area[k]查找空闲块;
    • 有空闲块:取出标记为已占用,直接返回
    • 无空闲块:向更大 order(k+1,k+2...)找空闲块
  3. 分裂 split:取出大块,切为一对伙伴。一块放回低 order 空闲链表,另一块继续递归分裂,直到得到 order=k 的块返回。

示例:申请 3 页,向上取 order=2(4 页),free_area 2 为空,则去 order=3(8 页)取块,分裂成两个 4 页。一个 4 页分配出去,另一个放入 free_area 2。

3. 释放流程(free)

释放起始地址p,order=k 的块:

  1. 将块标记空闲,插入free_area[k]
  2. 计算它的伙伴地址,检查伙伴是否空闲
    • 伙伴空闲:两个块从链表移除,合并成2k+12^{k+1}2k+1大块;k += 1,回到步骤 2递归向上合并
    • 伙伴已占用:停止合并,释放结束

释放时自动合并,不需要单独内存整理,这是伙伴系统最大优势。

4. 优缺点

优点

  1. 合并 / 分裂快,O(log⁡M)O(\log M)O(logM),M 是最大 order;位运算找伙伴,开销极低
  2. 大幅减少外部碎片;释放时自动合并相邻同大小空闲块
  3. 容易快速分配连续物理内存(DMA、大页、帧缓存场景)

缺点

  1. 内部碎片严重:申请大小不是 2 的幂,必须向上取整。例如申请 5 页,分配 8 页,3 页浪费;最坏浪费接近 50%
  2. 只能合并严格的伙伴块;普通相邻但不是同源分裂的空闲块不能合并(这是二进制伙伴的局限)

分配时:大块内存递归拆分;释放时,检查相邻伙伴页是否空闲,满足条件则向上合并。核心逻辑Split与Merge,用于管理物理内存碎片,满足DMA、THP透明大页对连续物理内存的需求。

六、内核分配器与用户态分配器

6.1 Buddy为什么不能直接malloc(24)

Buddy最小粒度是Page,直接分配会产生巨大内部碎片。Buddy只管理整页,小对象需要SLUB分配器,将Page切分成更小内核对象。

6.2 SLAB / SLUB分配器

Linux现代内核默认使用SLUB。伙伴系统 (buddy) 分配整页物理内存,slab 在整页之上做对象级内存分配 ,专门解决频繁创建销毁固定大小内核对象 的场景,用于task_struct、inode、dentry、file、socket等内核小对象。
#mermaid-svg-B0r6MmzvAE88JlaK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-B0r6MmzvAE88JlaK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-B0r6MmzvAE88JlaK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-B0r6MmzvAE88JlaK .error-icon{fill:#552222;}#mermaid-svg-B0r6MmzvAE88JlaK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-B0r6MmzvAE88JlaK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-B0r6MmzvAE88JlaK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-B0r6MmzvAE88JlaK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-B0r6MmzvAE88JlaK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-B0r6MmzvAE88JlaK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-B0r6MmzvAE88JlaK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-B0r6MmzvAE88JlaK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-B0r6MmzvAE88JlaK .marker.cross{stroke:#333333;}#mermaid-svg-B0r6MmzvAE88JlaK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-B0r6MmzvAE88JlaK p{margin:0;}#mermaid-svg-B0r6MmzvAE88JlaK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-B0r6MmzvAE88JlaK .cluster-label text{fill:#333;}#mermaid-svg-B0r6MmzvAE88JlaK .cluster-label span{color:#333;}#mermaid-svg-B0r6MmzvAE88JlaK .cluster-label span p{background-color:transparent;}#mermaid-svg-B0r6MmzvAE88JlaK .label text,#mermaid-svg-B0r6MmzvAE88JlaK span{fill:#333;color:#333;}#mermaid-svg-B0r6MmzvAE88JlaK .node rect,#mermaid-svg-B0r6MmzvAE88JlaK .node circle,#mermaid-svg-B0r6MmzvAE88JlaK .node ellipse,#mermaid-svg-B0r6MmzvAE88JlaK .node polygon,#mermaid-svg-B0r6MmzvAE88JlaK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-B0r6MmzvAE88JlaK .rough-node .label text,#mermaid-svg-B0r6MmzvAE88JlaK .node .label text,#mermaid-svg-B0r6MmzvAE88JlaK .image-shape .label,#mermaid-svg-B0r6MmzvAE88JlaK .icon-shape .label{text-anchor:middle;}#mermaid-svg-B0r6MmzvAE88JlaK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-B0r6MmzvAE88JlaK .rough-node .label,#mermaid-svg-B0r6MmzvAE88JlaK .node .label,#mermaid-svg-B0r6MmzvAE88JlaK .image-shape .label,#mermaid-svg-B0r6MmzvAE88JlaK .icon-shape .label{text-align:center;}#mermaid-svg-B0r6MmzvAE88JlaK .node.clickable{cursor:pointer;}#mermaid-svg-B0r6MmzvAE88JlaK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-B0r6MmzvAE88JlaK .arrowheadPath{fill:#333333;}#mermaid-svg-B0r6MmzvAE88JlaK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-B0r6MmzvAE88JlaK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-B0r6MmzvAE88JlaK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-B0r6MmzvAE88JlaK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-B0r6MmzvAE88JlaK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-B0r6MmzvAE88JlaK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-B0r6MmzvAE88JlaK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-B0r6MmzvAE88JlaK .cluster text{fill:#333;}#mermaid-svg-B0r6MmzvAE88JlaK .cluster span{color:#333;}#mermaid-svg-B0r6MmzvAE88JlaK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-B0r6MmzvAE88JlaK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-B0r6MmzvAE88JlaK rect.text{fill:none;stroke-width:0;}#mermaid-svg-B0r6MmzvAE88JlaK .icon-shape,#mermaid-svg-B0r6MmzvAE88JlaK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-B0r6MmzvAE88JlaK .icon-shape p,#mermaid-svg-B0r6MmzvAE88JlaK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-B0r6MmzvAE88JlaK .icon-shape .label rect,#mermaid-svg-B0r6MmzvAE88JlaK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-B0r6MmzvAE88JlaK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-B0r6MmzvAE88JlaK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-B0r6MmzvAE88JlaK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-B0r6MmzvAE88JlaK .buddy>*{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-B0r6MmzvAE88JlaK .buddy span{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-B0r6MmzvAE88JlaK .buddy tspan{fill:#0d47a1!important;}#mermaid-svg-B0r6MmzvAE88JlaK .slub>*{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-B0r6MmzvAE88JlaK .slub span{fill:#fff8e1!important;stroke:#fb8c00!important;stroke-width:1.5px!important;color:#e65100!important;}#mermaid-svg-B0r6MmzvAE88JlaK .slub tspan{fill:#e65100!important;}#mermaid-svg-B0r6MmzvAE88JlaK .obj>*{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-B0r6MmzvAE88JlaK .obj span{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-B0r6MmzvAE88JlaK .obj tspan{fill:#1b5e20!important;} Pages
Buddy Allocator
SLUB
Object
Object
Object
Object

概念
  1. kmem_cache(缓存描述符)
    每一类内核对象对应一个kmem_cache,比如task_struct缓存、inode 缓存。
    里面记录:对象大小、对齐、每个 slab 包含多少对象、构造 / 析构函数。
  2. Slab
    从 buddy 拿到的一个或多个连续物理页 ,把这一整块页切分成 N 个等大对象 。
    一个 slab 有 3 种状态:
  • 满(full):所有对象都被分配出去
  • 部分(partial):一部分对象在用,一部分空闲(优先从 partial 分配)
  • 空(free):全部对象空闲,可归还 buddy 伙伴系统
  1. 对象 (object):slab 里面最小单元,就是要分配的内核结构体实例。
  2. slab 的空闲标记
    早期 slab:用freelist数组记录 slab 内空闲对象索引;
    现代 SLUB(Linux 默认)简化:不再单独维护 freelist 数组,把下一个空闲对象指针直接存在空闲对象本身内存里。
分配流程 kmem_cache_alloc
  1. 在当前kmem_cache找 partial slab(有空闲对象的 slab)
  2. 从 partial slab 取出一个空闲对象,标记为已占用,返回对象指针
  3. 如果没有 partial slab:新建 slab
    • 调用 buddy 系统,申请若干连续物理页
    • 将页面切分成多个对象,可选执行对象构造 ctor初始化
    • 放入该 cache 的 partial 链表,再分配对象
  4. 分配失败:尝试内存回收(页面回收),失败返回 NULL
释放流程 kmem_cache_free
  1. 将对象标记回空闲,写回 freelist
  2. 所属 slab 状态:
    • 如果 slab 从「部分」变成完全空闲
      • 当系统内存紧张:把整个 slab 页面释放回 buddy 伙伴系统
      • 内存充裕:保留 slab,缓存对象,下次直接复用,减少 buddy 调用

重点:释放对象不会把页面立刻还给 buddy,slab 缓存页保留。

kmalloc(128, GFP_KERNEL)优先从SLUB缓存获取对象,SLUB缓存缺页时,才向下调用Page Allocator向Buddy申请物理页。

6.3 alloc_pages / kmalloc / vmalloc

  1. alloc_pages(gfp, order):直接调用Page Allocator,分配2^order物理连续页面;
  2. kmalloc():内核小块内存,虚拟连续,物理连续 ,底层SLUB+Buddy;分配标记GFP_KERNEL允许休眠,GFP_ATOMIC禁止休眠,用于中断上下文;
  3. vmalloc():虚拟地址连续,物理地址不要求连续。多个分散物理页,通过页表映射为一段连续内核虚拟地址。适合大块内核缓冲区,代价是TLB开销更高。

6.4 glibc malloc(用户态分配器)

malloc不是系统调用 ,是glibc实现的用户态库函数 ,ptmalloc2为现代glibc默认实现。

用户态分配器不会每次分配都陷入内核,会提前向内核申请大块虚拟内存,在用户态切分Chunk自行管理。

text 复制代码
Kernel
   │大块虚拟内存brk/mmap
   ▼
glibc allocator
text 复制代码
Heap
┌─────────┬───────────┬────────────┬──────────────┐
│ Chunk A │ Chunk B   │ Chunk C    │ Free Chunk   │
└─────────┴───────────┴────────────┴──────────────┘
Arena

Arena:分配区 ,是 glibc ptmalloc2 为了解决多线程 malloc 全局锁竞争而设计的独立内存管理实例,对应结构体 struct malloc_state。

早期 malloc 全局一把锁,多线程频繁 malloc/free 会严重串行阻塞;

每个 Arena 独立带锁,多个线程可以并行在不同 Arena 分配内存,降低锁竞争。

两类 Arena
  1. main_arena(主分配区)
    • 进程启动自动创建,主线程使用
    • 可以用 sbrk 扩展堆,也能用 mmap
    • 全局唯一,不在堆上,存在 libc 的静态数据段
  2. non-main arena(非主分配区 /sub-arena)
    • 子线程按需创建,只能用 mmap 向系统申请内存(每次 64MB)
    • 每个 arena 自带一把独立 mutex 锁,多个 arena 连成单向循环链表

Arena 数量上限

  • 32 位:2 * CPU核心数 + 1
  • 64 位:8 * CPU核心数

#mermaid-svg-5FRvMwTBBniwUuxV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5FRvMwTBBniwUuxV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5FRvMwTBBniwUuxV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5FRvMwTBBniwUuxV .error-icon{fill:#552222;}#mermaid-svg-5FRvMwTBBniwUuxV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5FRvMwTBBniwUuxV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5FRvMwTBBniwUuxV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5FRvMwTBBniwUuxV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5FRvMwTBBniwUuxV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5FRvMwTBBniwUuxV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5FRvMwTBBniwUuxV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5FRvMwTBBniwUuxV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5FRvMwTBBniwUuxV .marker.cross{stroke:#333333;}#mermaid-svg-5FRvMwTBBniwUuxV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5FRvMwTBBniwUuxV p{margin:0;}#mermaid-svg-5FRvMwTBBniwUuxV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5FRvMwTBBniwUuxV .cluster-label text{fill:#333;}#mermaid-svg-5FRvMwTBBniwUuxV .cluster-label span{color:#333;}#mermaid-svg-5FRvMwTBBniwUuxV .cluster-label span p{background-color:transparent;}#mermaid-svg-5FRvMwTBBniwUuxV .label text,#mermaid-svg-5FRvMwTBBniwUuxV span{fill:#333;color:#333;}#mermaid-svg-5FRvMwTBBniwUuxV .node rect,#mermaid-svg-5FRvMwTBBniwUuxV .node circle,#mermaid-svg-5FRvMwTBBniwUuxV .node ellipse,#mermaid-svg-5FRvMwTBBniwUuxV .node polygon,#mermaid-svg-5FRvMwTBBniwUuxV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5FRvMwTBBniwUuxV .rough-node .label text,#mermaid-svg-5FRvMwTBBniwUuxV .node .label text,#mermaid-svg-5FRvMwTBBniwUuxV .image-shape .label,#mermaid-svg-5FRvMwTBBniwUuxV .icon-shape .label{text-anchor:middle;}#mermaid-svg-5FRvMwTBBniwUuxV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5FRvMwTBBniwUuxV .rough-node .label,#mermaid-svg-5FRvMwTBBniwUuxV .node .label,#mermaid-svg-5FRvMwTBBniwUuxV .image-shape .label,#mermaid-svg-5FRvMwTBBniwUuxV .icon-shape .label{text-align:center;}#mermaid-svg-5FRvMwTBBniwUuxV .node.clickable{cursor:pointer;}#mermaid-svg-5FRvMwTBBniwUuxV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5FRvMwTBBniwUuxV .arrowheadPath{fill:#333333;}#mermaid-svg-5FRvMwTBBniwUuxV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5FRvMwTBBniwUuxV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5FRvMwTBBniwUuxV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5FRvMwTBBniwUuxV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5FRvMwTBBniwUuxV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5FRvMwTBBniwUuxV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5FRvMwTBBniwUuxV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5FRvMwTBBniwUuxV .cluster text{fill:#333;}#mermaid-svg-5FRvMwTBBniwUuxV .cluster span{color:#333;}#mermaid-svg-5FRvMwTBBniwUuxV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5FRvMwTBBniwUuxV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5FRvMwTBBniwUuxV rect.text{fill:none;stroke-width:0;}#mermaid-svg-5FRvMwTBBniwUuxV .icon-shape,#mermaid-svg-5FRvMwTBBniwUuxV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5FRvMwTBBniwUuxV .icon-shape p,#mermaid-svg-5FRvMwTBBniwUuxV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5FRvMwTBBniwUuxV .icon-shape .label rect,#mermaid-svg-5FRvMwTBBniwUuxV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5FRvMwTBBniwUuxV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5FRvMwTBBniwUuxV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5FRvMwTBBniwUuxV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-5FRvMwTBBniwUuxV .startEnd>*{fill:#E8F5E9!important;stroke:#2E7D32!important;stroke-width:2px!important;color:#1B5E20!important;}#mermaid-svg-5FRvMwTBBniwUuxV .startEnd span{fill:#E8F5E9!important;stroke:#2E7D32!important;stroke-width:2px!important;color:#1B5E20!important;}#mermaid-svg-5FRvMwTBBniwUuxV .startEnd tspan{fill:#1B5E20!important;}#mermaid-svg-5FRvMwTBBniwUuxV .process>*{fill:#E3F2FD!important;stroke:#1976D2!important;stroke-width:1.5px!important;color:#0D47A1!important;}#mermaid-svg-5FRvMwTBBniwUuxV .process span{fill:#E3F2FD!important;stroke:#1976D2!important;stroke-width:1.5px!important;color:#0D47A1!important;}#mermaid-svg-5FRvMwTBBniwUuxV .process tspan{fill:#0D47A1!important;}#mermaid-svg-5FRvMwTBBniwUuxV .decision>*{fill:#FFF8E1!important;stroke:#F9A825!important;stroke-width:1.5px!important;color:#795548!important;}#mermaid-svg-5FRvMwTBBniwUuxV .decision span{fill:#FFF8E1!important;stroke:#F9A825!important;stroke-width:1.5px!important;color:#795548!important;}#mermaid-svg-5FRvMwTBBniwUuxV .decision tspan{fill:#795548!important;}#mermaid-svg-5FRvMwTBBniwUuxV .action>*{fill:#F3E5F5!important;stroke:#8E24AA!important;stroke-width:1.5px!important;color:#4A148C!important;}#mermaid-svg-5FRvMwTBBniwUuxV .action span{fill:#F3E5F5!important;stroke:#8E24AA!important;stroke-width:1.5px!important;color:#4A148C!important;}#mermaid-svg-5FRvMwTBBniwUuxV .action tspan{fill:#4A148C!important;}#mermaid-svg-5FRvMwTBBniwUuxV .retry>*{fill:#FFEBEE!important;stroke:#C62828!important;stroke-width:1.5px!important;color:#B71C1C!important;}#mermaid-svg-5FRvMwTBBniwUuxV .retry span{fill:#FFEBEE!important;stroke:#C62828!important;stroke-width:1.5px!important;color:#B71C1C!important;}#mermaid-svg-5FRvMwTBBniwUuxV .retry tspan{fill:#B71C1C!important;} 成功
失败
有,取下一个
没有,全部失败
未达上限
已达上限
否
是
线程调用 malloc
遍历 arena 链表
尝试 lock 当前 arena
使用该 arena 分配
结束
还有下一个 arena?
arena 总数达上限?
新建 non-main arena
lock 新 arena
循环重试抢现有 arena 锁
抢到锁?

Arena 内部组成(层级)
复制代码
Arena(malloc_state)
├─ mutex:arena锁
├─ top chunk:arena的剩余连续堆顶
├─ fastbins:快速释放小块链表
├─ bins:unsorted bin + small bins + large bins
└─ heap:一个arena可以包含多个heap(mmap出来的heap segment)

Chunk:arena 管理的最小内存单元,用户 malloc 拿到的就是 chunk 的可用区域。

tcache(Thread Cache)

tcache(Thread Local Cache,线程本地缓存) 每个线程独立一份,无锁,专门加速小块内存 malloc/free,放在 Arena 上层。

Arena 是多线程共享、带锁;tcache 是线程私有、完全不用锁 。小对象malloc优先从tcache取空闲chunk,tcache缺失才进入Arena、争抢Arena锁;Arena空闲不足,才触发brk/mmap系统调用进入内核。

tcache -> Arena -> Kernel和PCP -> Buddy架构思想都是:局部缓存降低全局锁压力。

6.5 free() 后RSS不一定下降

free调用,仅标记Chunk为空闲,归还到tcache/bin/arena,不代表物理内存立刻还给内核。内核RSS(Resident Set Size,驻留物理内存)不会马上降低。

free后RSS不下降 ≠ 内存泄漏,是用户态分配器缓存策略。

6.6 大块分配:匿名mmap

当分配尺寸超过阈值,glibc使用mmap匿名映射,独立VMA。释放调用munmap,直接将虚拟区域归还内核,页面更容易回收。

6.7 brk / sbrk

brk 是内核系统调用(绝对地址);sbrk 是 glibc 在用户态封装的库函数(相对偏移),底层还是调用 brk ,用来移动 program break(程序断点),也就是堆的上边界水位线

  1. 堆是一块连续虚拟地址区域,在数据段上方;向上增长。
  2. 只有 main_arena(主分配区)使用 sbrk 扩展堆;non-main arena(子线程 arena)只能用 mmap 创建独立 64MB sub-heap,不能用 sbrk。
  3. 限制:只能回收堆最顶部连续空闲内存 。中间的空闲 chunk,哪怕很大,也没法通过 sbrk 还给内核,只能留在 ptmalloc 池里复用(内存碎片根源)。
    • 只有 top chunk 空闲大小超过阈值(默认 128KB),malloc_trim 或者 free 时才会调用 sbrk 收缩堆、归还内存给内核。

传统堆使用brk系统调用,修改program break指针,向上扩展堆VMA。现代应用不建议直接调用brk,统一封装在malloc接口下。

复制代码
malloc
├─ 优先走线程私有tcache(无锁)
├─ tcache空 → 找arena分配
│  ├─ arena内部空闲chunk不够,需要向内核申请内存
│  │   ├─ main_arena:调用sbrk抬高program break,连续扩展堆
│  │   └─ non-main arena:mmap新建sub-heap(64MB)
└─ 超大分配(>M_MMAP_THRESHOLD 默认128KB):直接mmap匿名映射,free时munmap直接还给内核,不走任何bin/tcache

6.8 malloc(100)三种场景

  1. tcache命中:直接返回空闲chunk,0次系统调用;
  2. tcache miss,Arena有空闲chunk:切分chunk返回,不进入内核;
  3. Arena耗尽:调用brk/mmap,内核新建VMA。此时只分配虚拟地址,物理页仍然延迟到第一次访问触发缺页分配。

七、内存压力、页面回收、Compaction、OOM

7.1 Page Reclaim页面回收

内存不足时,Linux不会直接返回分配失败,尝试回收可回收页面。页面分为可回收与不可回收:

  • 可回收:Page Cache文件缓存、可Swap匿名内存;
  • 不可回收:内核锁定页面、内核代码、mlock锁定用户内存。

7.2 Page Cache

Linux利用空闲内存缓存文件IO。读文件时,磁盘内容加载到Page Cache。Clean Page Cache,磁盘存在副本,内存压力下可直接丢弃;Dirty Page Cache需要先回写磁盘,再回收页面。Page Cache是Linux提升文件IO吞吐的核心机制。

7.3 Anonymous匿名内存 & Swap

malloc拿到的匿名内存(anonymous memory) :没有关联磁盘上的普通文件,物理内存不够的时候,内核可以把这部分内存页写到 Swap(交换分区 / 交换文件)腾物理内存;之后程序再访问这一页,CPU 缺页异常,内核做SwapIn,把 Swap 上的数据读回物理内存,程序继续运行。

1. 匿名页(匿名内存)
  • 匿名:不绑定任何磁盘文件 。mmap(MAP_ANONYMOUS)、malloc(底层 brk/mmap)分配出来的堆内存就是匿名页。
  • 对比:mmap映射一个磁盘文件得到的是文件映射页,它的后端是磁盘文件,内存紧张时可以直接丢弃,需要时从原文件读;匿名页没有原文件,所以只能写到 Swap 保存数据。

malloc 不是直接分配物理内存:只是在进程虚拟地址空间 里划出一块地址。第一次读写的时候才触发缺页,内核分配物理页框(延迟分配,写时复制 COW 配套机制)。

2. 内存紧张 → 匿名页换出(Swap Out)

物理内存不够用的时候,内核的页回收逻辑会挑选一些冷页(很久没访问):

  1. 对文件页:脏页写回原文件、干净页直接丢掉;
  2. 对匿名页 :没有原始文件可以回写,内核只能把页内容拷贝到 Swap 分区 /swapfile,然后释放这块物理内存。
  3. 页表项会被标记:这一页不在内存,数据在 Swap 的某个位置。

这一步叫 SwapOut(换出)。换出之后,进程的虚拟地址还在,但对应的物理内存已经被收走。

3. 再次访问该页 → 缺页异常 → SwapIn(换入)

进程读写这个虚拟地址:

  1. MMU 查页表,发现有效位为 0,触发缺页异常(page fault);
  2. 内核进入缺页处理函数,判断这是匿名页,并且已经被换到 Swap;
  3. 执行 SwapIn:从磁盘 Swap 位置读取页面数据,分配新物理页框,把数据加载进去;
  4. 更新页表,指向新物理页;
  5. 返回用户态,重新执行触发异常的那条指令,程序无感继续运行。
  1. Swap 不是必须的:系统可以无 Swap。此时内存紧张,匿名页不能换出,内核会触发 OOM,杀掉进程释放内存。
  2. 换入换出代价极高:磁盘 IO,比内存慢上万倍。大量 SwapIn/SwapOut 就是常说的抖动(thrashing),系统卡死。
  3. 不是所有匿名页都会被换出:可以用mlock锁定内存,被锁定的匿名页永远留在物理内存,不会被 SwapOut。
  4. 写时复制 fork:子进程的匿名页一开始和父进程共享物理页;写的时候才拷贝。拷贝出来的新页依然是匿名页,同样可以被换入换出。

7.4 kswapd后台回收线程

Linux 把同一个 NUMA 节点内的物理内存,按硬件访问限制划分成若干连续物理地址区间,每个区间就是一个Zone(内存域) 。伙伴系统、页面回收、kswapd、Swap 换页,全部是以 Zone 为单位管理

每个Zone维护三个水位线:High / Low / Min。

  1. high:空闲页充足,kswapd 休眠,不做回收
  2. low:空闲页低于 low → 唤醒 kswapd 后台回收(扫描 LRU,匿名页 SwapOut、文件页回收)
  3. min :低于 min,kswapd 来不及,直接同步回收;再失败触发 OOM Killer
text 复制代码
Free Memory
     │
     ▼
低于Low Watermark
     │
     ▼
唤醒kswapd内核线程,后台异步回收页面
     │
     ▼
直到空闲内存回升至High Watermark,kswapd休眠

kswapd是后台守护线程,目标提前回收内存,尽量避免分配路径直接阻塞。kswapd何时运行,由CPU调度器决定。

7.5 Direct Reclaim直接回收

Zone 空闲内存跌破 watermark[min],kswapd 后台回收已经跟不上 。此时发起内存分配的当前线程,不再等待 kswapd,自己在 alloc_pages 分配路径里同步执行页面回收 ,这就是 Direct Reclaim(直接回收)。

线程原地阻塞,一边回收页面一边尝试凑出空闲页;回收过程会带来巨大 IO 抖动(Jitter),是业务延迟尖峰的重要来源。

  1. 空闲 < low:唤醒 kswapd 内核线程,后台异步回收,分配线程照常走分配,不阻塞。kswapd 在后台扫 LRU、换出匿名页、回写脏文件页,把空闲内存拉回 high 水位,之后 kswapd 休眠。
  2. 空闲 < min:kswapd 来不及释放足够页,分配线程进入 Direct Reclaim。分配线程自己执行回收逻辑,线程被阻塞,直到回收释放出足够页面或者回收失败。
Direct Reclaim 完整流程
  1. alloc_pages 进入,检查目标 Zone 水位,发现空闲页 < min;
  2. 进入直接回收路径 __alloc_pages_direct_reclaim;
  3. 调用 shrink_zones → shrink_lruvec,扫描当前 Zone 的 LRU 链表:
    • 文件干净页:直接释放
    • 文件脏页:触发回写磁盘
    • 匿名页:必须 SwapOut,把页写入 Swap 磁盘(这一步最耗时,磁盘 IO)
  4. 每回收一批页面,再次尝试alloc_pages;
    • 成功拿到页:分配返回,线程继续运行;
    • 反复回收仍然凑不出内存:直接回收失败,进入 OOM Killer。

7.6 实时系统视角:内存分配带来的抖动

  • kswapd 是后台内核线程,就算有 SwapOut IO,只会占用后台资源,用户业务线程不受直接阻塞;
  • Direct Reclaim 是用户进程 / 内核线程原地等待 IO:业务代码执行到 malloc,卡在分配路径,等待 Swap 写盘;Swap IO 耗时毫秒甚至几十 ms,业务延迟瞬间飙升,出现延迟尖峰。

机器人视觉、控制等高实时场景,运行时new/malloc/vector::resize会引入不确定延迟尖峰:

text 复制代码
malloc
  ↓
Allocator Slow Path
  ↓
内核分配
  ↓
Page Fault
  ↓
Direct Reclaim
  ↓
线程休眠唤醒
  ↓
Latency Spike → Jitter

工程解决方案:内存池、对象池、预分配Buffer、mlock锁定内存,运行时不再动态分配,消除缺页与回收抖动。

7.7 两层内存碎片

  1. 用户态分配器碎片:总空闲内存足够,但没有足够大连续Chunk。例如空闲96B,申请80B,碎片导致分配失败;
  2. 物理内存碎片(Buddy碎片) :大量离散空闲Page,但是没有连续物理Page。即使总空闲页足够,无法满足大块连续物理内存请求(DMA、THP)。

7.8 Memory Compaction内存规整

为解决物理碎片,Linux执行内存规整:迁移页面,把占用页面压缩到Zone一端,空闲页合并为大块连续物理内存。

复制代码
Before: U F U F U F U F
After:  U U U U F F F F

规整分为异步后台规整、同步规整(分配请求路径触发)。

现象:系统free内存很高,但是无法分配大段连续物理页,大概率物理碎片。

7.9 OOM Killer

当内存分配长期无法取得进展时,内核在满足相应条件的情况下可能进入OOM处理流程,并根据OOM评分等因素选择进程终止以释放内存。

但并非所有页面分配失败都会触发OOM Killer:分配行为还受到GFP Flags、分配Order、Memcg限制以及调用上下文等因素影响,例如部分High-order分配或禁止重试的分配可能直接失败并返回NULL,而不会启动OOM Killer。

7.10 Overcommit内存超分配:malloc成功不等于物理内存已经准备好

Linux支持Memory Overcommit,但是否接受一个远大于实际RAM+Swap的虚拟内存申请,取决于vm.overcommit_memory策略:

  • 0:启发式Overcommit,也是Linux常见默认模式;允许一定程度的超分配,但明显不合理的大型申请仍可能被拒绝;
  • 1:Always Overcommit,内核尽量允许虚拟地址空间申请,直到后续真正消耗内存时出现压力;
  • 2:严格Commit Accounting,根据Swap和配置的Commit Limit限制可提交内存。

因此,malloc(100GB)即使机器没有100GB可用物理内存,有可能返回成功,但绝不能认为一定成功。即使malloc已经返回非空指针,也只代表当前虚拟内存申请被分配器和内核接受,并不意味着对应大小的物理RAM已经全部准备完成。

后续程序真正写入这些页面时,会逐步建立物理页映射;如果持续产生的实际内存需求超过系统能够承受的范围,则可能进入页面回收、Swap,最终在满足OOM条件时触发OOM处理。

malloc返回成功 ≠ 对应大小的物理内存已经分配并得到绝对保证。

八、内存管理子系统与CPU调度器协作

  1. CPU调度器:管理就绪线程队列,决定线程调度、切换、休眠唤醒;
  2. MM子系统:内存映射、缺页处理、页面回收;

二者典型协作场景:线程访问未驻留内存,触发Page Fault,需要磁盘IO加载页面:
#mermaid-svg-kA3Hl8gFZreWZb6A{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kA3Hl8gFZreWZb6A .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kA3Hl8gFZreWZb6A .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kA3Hl8gFZreWZb6A .error-icon{fill:#552222;}#mermaid-svg-kA3Hl8gFZreWZb6A .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kA3Hl8gFZreWZb6A .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kA3Hl8gFZreWZb6A .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kA3Hl8gFZreWZb6A .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kA3Hl8gFZreWZb6A .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kA3Hl8gFZreWZb6A .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kA3Hl8gFZreWZb6A .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kA3Hl8gFZreWZb6A .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kA3Hl8gFZreWZb6A .marker.cross{stroke:#333333;}#mermaid-svg-kA3Hl8gFZreWZb6A svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kA3Hl8gFZreWZb6A p{margin:0;}#mermaid-svg-kA3Hl8gFZreWZb6A .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kA3Hl8gFZreWZb6A .cluster-label text{fill:#333;}#mermaid-svg-kA3Hl8gFZreWZb6A .cluster-label span{color:#333;}#mermaid-svg-kA3Hl8gFZreWZb6A .cluster-label span p{background-color:transparent;}#mermaid-svg-kA3Hl8gFZreWZb6A .label text,#mermaid-svg-kA3Hl8gFZreWZb6A span{fill:#333;color:#333;}#mermaid-svg-kA3Hl8gFZreWZb6A .node rect,#mermaid-svg-kA3Hl8gFZreWZb6A .node circle,#mermaid-svg-kA3Hl8gFZreWZb6A .node ellipse,#mermaid-svg-kA3Hl8gFZreWZb6A .node polygon,#mermaid-svg-kA3Hl8gFZreWZb6A .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kA3Hl8gFZreWZb6A .rough-node .label text,#mermaid-svg-kA3Hl8gFZreWZb6A .node .label text,#mermaid-svg-kA3Hl8gFZreWZb6A .image-shape .label,#mermaid-svg-kA3Hl8gFZreWZb6A .icon-shape .label{text-anchor:middle;}#mermaid-svg-kA3Hl8gFZreWZb6A .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kA3Hl8gFZreWZb6A .rough-node .label,#mermaid-svg-kA3Hl8gFZreWZb6A .node .label,#mermaid-svg-kA3Hl8gFZreWZb6A .image-shape .label,#mermaid-svg-kA3Hl8gFZreWZb6A .icon-shape .label{text-align:center;}#mermaid-svg-kA3Hl8gFZreWZb6A .node.clickable{cursor:pointer;}#mermaid-svg-kA3Hl8gFZreWZb6A .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kA3Hl8gFZreWZb6A .arrowheadPath{fill:#333333;}#mermaid-svg-kA3Hl8gFZreWZb6A .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kA3Hl8gFZreWZb6A .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kA3Hl8gFZreWZb6A .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kA3Hl8gFZreWZb6A .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kA3Hl8gFZreWZb6A .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kA3Hl8gFZreWZb6A .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kA3Hl8gFZreWZb6A .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kA3Hl8gFZreWZb6A .cluster text{fill:#333;}#mermaid-svg-kA3Hl8gFZreWZb6A .cluster span{color:#333;}#mermaid-svg-kA3Hl8gFZreWZb6A div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kA3Hl8gFZreWZb6A .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kA3Hl8gFZreWZb6A rect.text{fill:none;stroke-width:0;}#mermaid-svg-kA3Hl8gFZreWZb6A .icon-shape,#mermaid-svg-kA3Hl8gFZreWZb6A .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kA3Hl8gFZreWZb6A .icon-shape p,#mermaid-svg-kA3Hl8gFZreWZb6A .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kA3Hl8gFZreWZb6A .icon-shape .label rect,#mermaid-svg-kA3Hl8gFZreWZb6A .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kA3Hl8gFZreWZb6A .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kA3Hl8gFZreWZb6A .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kA3Hl8gFZreWZb6A :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-kA3Hl8gFZreWZb6A .mm>*{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-kA3Hl8gFZreWZb6A .mm span{fill:#e3f2fd!important;stroke:#1e88e5!important;stroke-width:1.5px!important;color:#0d47a1!important;}#mermaid-svg-kA3Hl8gFZreWZb6A .mm tspan{fill:#0d47a1!important;}#mermaid-svg-kA3Hl8gFZreWZb6A .cpu>*{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-kA3Hl8gFZreWZb6A .cpu span{fill:#e8f5e9!important;stroke:#43a047!important;stroke-width:1.5px!important;color:#1b5e20!important;}#mermaid-svg-kA3Hl8gFZreWZb6A .cpu tspan{fill:#1b5e20!important;} CPU 调度器
内存管理子系统
触发缺页
线程 A 阻塞
等待 IO 完成
就绪
Page Fault
需要磁盘 IO
处理缺页
IO 完成

唤醒 Thread A

加入就绪队列
Thread A Running
线程 A 阻塞

进入睡眠状态
Scheduler 切换 CPU

执行 Thread B
Scheduler 决定

Thread A 重新获得 CPU

kswapd是内核线程,MM子系统负责唤醒kswapd变为就绪态;kswapd什么时候执行,由CPU调度器决定。

工程提到的内存调度、NUMA调度,本质是页面放置、页面迁移、回收策略,属于MM子系统策略,不是调度器。

总结

text 复制代码
Linux Memory Management
│
├── Process Virtual Memory
│   ├── mm_struct
│   ├── VMA
│   ├── mmap
│   ├── brk
│   └── Memory Permission
│
├── Address Translation
│   ├── Page Table
│   │   ├── PGD
│   │   ├── P4D
│   │   ├── PUD
│   │   ├── PMD
│   │   └── PTE
│   │
│   ├── MMU
│   ├── TLB
│   └── Page Walk
│
├── Page Fault
│   ├── Demand Paging
│   ├── Anonymous Page
│   ├── File-backed Page
│   └── Copy-on-Write(fork核心机制)
│
├── Physical Memory
│   ├── NUMA Node
│   ├── Zone
│   ├── Page / Folio
│   ├── PCP
│   └── Buddy Allocator
│
├── Kernel Allocation
│   ├── alloc_pages
│   ├── kmalloc
│   ├── SLAB / SLUB
│   └── vmalloc
│
├── Userspace Allocator
│   ├── glibc malloc ptmalloc
│   ├── Chunk
│   ├── tcache
│   ├── Arena
│   ├── Bins
│   ├── brk
│   └── mmap
│
└── Memory Pressure
    ├── Page Cache
    ├── Page Reclaim
    ├── kswapd
    ├── Direct Reclaim
    ├── Swap
    ├── Memory Compaction
    └── OOM Killer
相关推荐
system_error_x1 小时前
自动化常规代码辅助系统
运维·自动化·log4j
重生之小比特1 小时前
【Linux系统】08 进程切换
linux·运维·服务器
讯捷蓝达1 小时前
戴尔 R750XS服务器不开机, 主板 Pfault fail-safe 电压异常、CPU1 VCCIO PG 电压超出范围维修
运维·服务器
昌原的儿子LEO1 小时前
嵌入式 Linux I2C 驱动开发核心知识总结:设备树与 platform 架构全解析
linux·驱动开发·架构
程序员-Benothing1 小时前
Linux内存管理详解:free、vmstat、buff/cache、swap
linux·运维·服务器
_不会dp不改名_2 小时前
leetcode_3727 最大平方交替和
linux·算法·leetcode
Lsetea2 小时前
OpenSSL报certificate revoked:error 23与CRL吊销层级排查
linux·https·ssl证书·openssl·crl
4SAPI2 小时前
多模型API调用实战:一个项目接入GPT、Claude和DeepSeek
linux·人工智能·gpt·php
j7~2 小时前
【仿 RabbitMQ 项目】发布订阅消息队列 (篇八):交换机数据管理模块,分层类设计、SQLite 回调原理与代码实现
服务器·网络·数据库·消息队列·交换机·交换机数据管理·sqlite回调原理