虚拟内存
由 操作系统内核 + MMU(内存管理单元)硬件 共同实现的 映射框架。
每个进程在启动时,操作系统根据虚拟内存机制,为该进程创建一张独立的页表,这就是该进程的虚拟地址空间。
注意:
虚拟内存的映射是单向的:虚拟地址 → 物理地址。硬件页表只支持这个方向。反向查询(物理地址 → 虚拟地址)仅存在于内核的软件管理结构中(如 RMAP),且不对外暴露。
# 查看你的 CPU 支持的虚拟地址位数
cat /proc/cpuinfo | grep -i "address sizes"
# 结果
address sizes : 46 bits physical, 48 bits virtual
address sizes : 46 bits physical, 48 bits virtual
48 bits virtual 表示 CPU 支持 48 位虚拟地址(2^48 256TB)
Linux 内核把 256TB(2^48) 的虚拟地址空间从中间一分为二:
0128TB 用户空间(User Space)
128256TB 内核空间(User Space)
1.为什么需要虚拟内存?
2.为什么虚拟内存那么大?
给操作系统内核提供巨大的操作空间(映射所有硬件)。
让程序永远不用操心物理内存的碎片和大小,程序永远认为自己拥有一块连续、巨大且干净的内存。
简化编译器、链接器和操作系统的设计,让每个进程都能固定在同一个基地址运行。
3.是否会出现两个虚拟地址映射到了同一个物理地址?
大部分虚拟地址处于“未映射”状态:页表里绝大多数条目是空的(标记为“无效”)。进程的页表就像一张巨大的地图,但上面只标注了少数几个实际存在的房子(物理页),其他地方都是“待开发空地”。
访问未映射地址 → 段错误(Segmentation Fault):如果程序跑飞,试图访问一个没有映射的虚拟地址,MMU 在查页表时找不到对应物理页,会触发一个硬件异常(缺页中断)。操作系统捕获后,会向该进程发送 SIGSEGV 信号,通常导致进程崩溃(“段错误”),从而保护系统不崩溃。
按需分配(Demand Paging):即使程序通过 malloc 申请了 100GB 的虚拟内存,操作系统也只是在页表里做记录(预留虚拟地址),并不立即分配物理内存。只有当你真正向这块地址写入数据时,操作系统才从 16GB 的物理内存中“挤”出一个空闲页给你用。如果物理内存真的用光了,操作系统会启动 OOM Killer(Out-of-Memory Killer),根据一系列规则杀掉占用内存最多的进程,以维持系统稳定性。
IO多路复用
I/O 多路复用 = 一个线程/进程,同时监控多个 I/O 操作,哪个准备好了就处理哪个。