内存管理
问题
操作系统如何管理内存?分页和分段有什么区别?
答案
内存管理方式
| 方式 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 连续分配 | 进程占连续内存块 | 简单 | 外部碎片 |
| 分页 | 物理内存分为固定大小的页框 | 无外部碎片 | 内部碎片、页表开销 |
| 分段 | 按逻辑段分配(代码段、数据段) | 符合逻辑结构 | 外部碎片 |
| 段页式 | 先分段再分页 | 兼具优点 | 复杂 |
分页机制
虚拟地址 = 页号 + 页内偏移
虚拟页号 → 页表 → 物理页框号 → 物理地址
- 页(Page):虚拟内存的固定大小块(通常 4KB)
- 页框(Frame):物理内存的固定大小块
- 页表(Page Table):虚拟页号 → 物理页框号的映射表
- TLB:页表的高速缓存,加速地址翻译
虚拟内存
每个进程拥有独立的虚拟地址空间,操作系统通过页表映射到物理内存。
核心好处:
- 隔离:进程间内存互不影响
- 共享:多个进程可映射同一物理页(共享库)
- 按需加载:不用一次把程序全部加载到内存
页面置换算法
当物理内存不够时,需要把某些页换出到磁盘(swap),换入需要的页。
| 算法 | 原理 | 性能 |
|---|---|---|
| FIFO | 先进先出 | 差 |
| LRU | 淘汰最近最少使用的页 | 好(实现复杂) |
| LFU | 淘汰访问频率最低的页 | 好 |
| Clock | 近似 LRU(循环+引用位) | 较好(实用) |
| OPT | 淘汰最长时间不会被访问的页 | 最优(无法实现) |
常见面试问题
Q1: JVM 内存和操作系统内存的关系?
答案:
JVM 进程向操作系统申请一块内存(通过 -Xms/-Xmx 指定堆大小),然后在这块内存中自行管理堆、栈、方法区等。
- JVM 堆内存 → 操作系统为进程分配的物理内存/虚拟内存
- GC 回收的是 JVM 堆中的对象,不直接归还给操作系统
- 堆外内存(DirectByteBuffer)直接向操作系统申请
详见 JVM 内存结构。
Q2: 什么是内存碎片?
答案:
- 外部碎片:空闲内存总量够,但不连续,无法分配大块内存(分段会产生)
- 内部碎片:分配的内存块大于实际需要,多余部分浪费(分页会产生,因为按固定页大小分配)
分页消除了外部碎片,但会产生少量内部碎片(最后一页可能没用满)。
Q3: 为什么 Linux 的 swap 空间太大反而不好?
答案:
频繁的页面换入换出(swap)会导致严重的磁盘 IO(称为"抖动"),性能急剧下降。在 Java 应用中,GC 需要扫描/拷贝堆内存,如果堆被 swap 到磁盘,GC 暂停时间会从毫秒级飙升到秒级。
生产环境建议:关闭 swap 或设置 vm.swappiness=0。