Skip to content

虚拟内存系统 ​

为了方便管理程序运行时使用的内存空间,
memory management unit(mmu)内存管理单元,辅助操作系统管理内存。

内存类型描述
物理内存实际内存空间
虚拟内存应用程序可以看到并使用的内存空间

内存寻址范围 ​

由地址总线范围和数据总线大小决定
例如:
内存地址总线长度20bit,内存单元8bit,则访问2^20 * 8bit的内存空间,即2MB。
内存地址总线长度32bit,内存单元8bit,则访问2^32 * 8bit的内存空间,即4GB。

地址类型 ​

地址类型描述
逻辑地址机器语言指令使用的地址,指定一个操作数的地址或一条指令的地址
线性地址线性地址是一个无符号整数,范围0x00~0xffffffff(ffffffff),
由逻辑地址的段基址+段偏移计算得到
若无分页机制,线性地址即物理地址
物理地址内存单元的实际地址,用于芯片级内存单元寻址

地址转换 ​

逻辑地址-->线性地址-->物理地址,实际转换流程由MMU操作
mem

分页机制 ​

将虚拟内存空间和物理内存空间按固定大小划分成若干页
只将程序需要使用的页映射到物理内存
内存

类型说明
页框page frame,分页单元把所有的RAM物理内存分成固定长度的页框,长度也是4KB或更大
页分页单元将线性地址分成以固定长度位单位的组,称为页(page)。
页内部连续,映射是以页位基本单位。

4级页表 ​

x86_64采用四级页表,来管理标准4KB页。
在x64体系中用48位的虚拟寻址
理论上48位地址长度可以管理512TB的地址空间
不过x86_64四级页表只使用了256TB的虚拟地址空间。
详见linux 4级内存页表虚拟地址空间范围
address48bit线性地址划分为下面几部分:

字段长度描述
OFFSET12bit页内偏移量,对应4K范围
PT(Page Table)9bit
PDT(Page Directory Table)9bit每个表4K,内含512个PDE结构,每个8字节
PDPT(Page Directory Pointer Table)9bit及表内的PDPTE结构
PML4T(Page Map Level4 Table)9bit及表内的PML4E结构
f/016bit全填充0或f

同x86 32位一样,系统使用CR3存储页表的基地址,即PML4T的物理基地址。x86_64支持多种页面大小:

1)4K页面:使用PML4T,PDPT,PDT和PT 四级页转化表结构; 2)2M页面:使用PML4T,PDPT 和PDT三级页转化表结构; 3)1G 页面:使用PML4T和PDPT二级页表转化结构。 详细的地址转换过程,在下面的linux 系统分页机制实现再阐述。

虚拟地址映射到物理地址的每一个映射叫叫页表实体(page table entry,PTE)。

TLB ​

translation lookaside buffer,转换旁路缓存。 CPU的MMU使用该缓存存储操作系统最近使用的映射。

转换过程 ​

页表转换

当虚拟地址需要转换到物理地址时,先查询TLB。 如果TLB命中,则返回对应的物理地址,并继续访问物理内存。 如果不命中,则mmu或者TLB缺失处理程序将会去页表查否是否存在该映射。 如果存在,将其写回到TLB。

TTW,translation table walk,转换表漫游。当tlb中不存在虚拟地址和物理地址的转换关系时,通过访问内存中的转换表来获取虚拟地址和物理地址的对应关系。 TT,转换表,一般为多级页表。

缓存 ​

buffer缓存 ​

块设备的写缓冲,将随机写合并为顺序写,减少磁盘 I/O 次数。

bash
# 查看 buffer/cache 使用量
free -h
cat /proc/meminfo | grep -E "Buffers|Cached"

页缓存 ​

磁盘文件内容的内存缓存(Page Cache),读文件时先查 page cache,命中则不访问磁盘。

bash
# 查看 page cache 占用
cat /proc/meminfo | grep -E "Cached|Dirty|Writeback"

# 手动释放页缓存(生产环境慎用)
echo 1 > /proc/sys/vm/drop_caches   # 释放 page cache
echo 2 > /proc/sys/vm/drop_caches   # 释放 dentries/inodes
echo 3 > /proc/sys/vm/drop_caches   # 释放以上所有

交换分区(Swap) ​

当物理内存不足时,内核将部分内存页换出(swap out)到磁盘上的交换分区。

bash
# 查看 swap 状态
swapon --show
free -h
cat /proc/meminfo | grep Swap

# 创建并启用 swap 文件
dd if=/dev/zero of=/swapfile bs=1G count=4
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# 永久生效(写入 /etc/fstab)
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# 关闭 swap
swapoff /swapfile

swappiness:控制内核使用 swap 的积极程度,值 0-100,越高越积极。

bash
# 查看当前值(默认 60)
cat /proc/sys/vm/swappiness

# 临时修改
echo 10 > /proc/sys/vm/swappiness

# 永久修改
echo 'vm.swappiness=10' >> /etc/sysctl.conf
sysctl -p

硬件缓存 ​

CPU 片上缓存,按访问速度分级:L1 Cache(~1ns)→ L2 Cache(~5ns)→ L3 Cache(~20ns)


区 ​

根据使用功能,将页划分为不同的区。

区(Zone)说明
ZONE_DMA可用于 ISA 设备 DMA 的低端内存(< 16MB)
ZONE_DMA32AMD64 上可用于 32 位 DMA 的内存(< 4GB)
ZONE_NORMAL常规映射内存区域
ZONE_HIGHMEM32 位系统高于 896MB 的物理内存(x86_64 不存在)
ZONE_MOVABLE可迁移页,用于内存热插拔
bash
# 查看各 Zone 信息
cat /proc/zoneinfo

内存分配 ​

物理内存分配 ​

内核通过**伙伴系统(Buddy System)**分配连续物理页,按 2^n 页为单位管理。

bash
# 查看伙伴系统状态
cat /proc/buddyinfo

slab 分配器:在伙伴系统之上,为内核小对象(task_struct、inode 等)提供高效分配。

bash
# 查看 slab 使用情况
slabtop
cat /proc/slabinfo

用户空间内存分配 ​

分配来源说明
malloc()C 库分配,小块用 brk/sbrk 扩堆,大块用 mmap
mmap()直接向内核申请内存映射区域
brk()/sbrk()移动堆顶指针

OOM Killer ​

当系统内存严重不足时,OOM Killer(Out-Of-Memory Killer)会选择并杀死某个进程以释放内存。

OOM 触发与日志 ​

bash
# 查看 OOM 相关内核日志
dmesg | grep -i "oom\|out of memory\|killed process"
journalctl -k | grep -i oom

oom_score ​

内核根据进程的内存使用、运行时间等计算 oom_score(0-1000),分数越高越容易被杀。

bash
# 查看进程的 oom_score
cat /proc/<pid>/oom_score

# 查看 oom_score_adj(调整值,范围 -1000~1000)
cat /proc/<pid>/oom_score_adj

保护关键进程 ​

bash
# 设置为 -1000 可完全免除 OOM 杀死(需 root)
echo -1000 > /proc/<pid>/oom_score_adj

# 或通过 systemd 服务配置
# /etc/systemd/system/myservice.service
[Service]
OOMScoreAdjust=-1000

禁用 OOM Killer(极端情况,慎用) ​

bash
# 禁用(系统可能挂死)
echo 1 > /proc/sys/vm/panic_on_oom

# 内存不足时触发 panic 并重启
echo 1 > /proc/sys/kernel/panic_on_oops

内存监控命令 ​

bash
# 综合概览
free -h

# 详细内存信息
cat /proc/meminfo

# 进程内存使用(VSZ: 虚拟内存,RSS: 常驻内存)
ps aux --sort=-%mem | head -15

# 进程内存映射详情
pmap -x <pid>
cat /proc/<pid>/maps
cat /proc/<pid>/smaps

# 实时内存监控
vmstat 1
top (按 M 按内存排序)
htop

# 内存使用统计(按进程)
smem -r -k | head -20

Linux的进程地址空间一,兰新宇
Linux的进程地址空间二,兰新宇
Four-level page tables
Five-level page tables