01. 基本概念
内存管理基础
内存管理是操作系统的核心功能之一,负责管理计算机的主存储器,为进程分配和回收内存空间,确保内存的安全使用。
程序装入与链接
程序装入过程
程序从外存调入内存的过程称为程序装入,主要包括以下步骤:
- 编译阶段:将源代码编译成目标代码
- 链接阶段:将多个目标模块链接成可执行程序
- 装入阶段:将可执行程序装入内存
链接方式
1. 静态链接
// 编译时链接所有库函数
gcc -static program.c -o program
- 优点:执行速度快,不依赖外部库
- 缺点:可执行文件大,内存利用率低
2. 动态链接
// 运行时链接库函数
gcc program.c -o program
- 优点:节省内存,便于库函数更新
- 缺点:执行速度稍慢,依赖外部库
3. 运行时动态链接
// 程序运行时根据需要加载库
dlopen("libmath.so", RTLD_LAZY);
装入方式
1. 绝对装入
- 程序装入到指定的绝对地址
- 适用于单道程序系统
- 地址在编译时确定
2. 可重定位装入
- 程序装入到内存的任意位置
- 需要重定位寄存器
- 支持多道程序设计
3. 动态运行时装入
- 程序在运行时才确定装入位置
- 支持虚拟内存管理
- 地址转换延迟到访问时进行
逻辑地址与物理地址空间
地址空间概念
逻辑地址空间:
- 由 CPU 生成的地址
- 从 0 开始的连续地址空间
- 程序员可见的地址
物理地址空间:
- 内存单元的实际地址
- 可能不连续
- 硬件可见的地址
地址转换过程
逻辑地址 → 地址转换机构 → 物理地址
地址转换机构:
- 重定位寄存器:基址寄存器
- 页表:分页系统中的地址映射
- 段表:分段系统中的地址映射
地址转换示例
基址重定位:
// 逻辑地址:1000
// 基址寄存器:5000
// 物理地址 = 逻辑地址 + 基址 = 1000 + 5000 = 6000
分页地址转换:
// 逻辑地址:0x1234
// 页号:0x12,页内偏移:0x34
// 通过页表查找物理块号
// 物理地址 = 物理块号 × 页大小 + 页内偏移
内存保护
保护机制
1. 界限寄存器保护
// 基址寄存器:5000
// 界限寄存器:2000
// 有效地址范围:[5000, 7000)
if (address < base || address >= base + limit) {
// 地址越界,产生保护性中断
raise_protection_fault();
}
2. 页表保护位
typedef struct {
int frame_number; // 物理块号
int valid; // 有效位
int read; // 读权限
int write; // 写权限
int execute; // 执行权限
} PageTableEntry;
3. 段表保护位
typedef struct {
int base; // 段基址
int limit; // 段长度
int read; // 读权限
int write; // 写权限
int execute; // 执行权限
} SegmentTableEntry;
保护类型
1. 越界保护
- 检查访问地址是否在允许范围内
- 防止访问其他进程的内存空间
2. 权限保护
- 读权限:允许读取数据
- 写权限:允许修改数据
- 执行权限:允许执行代码
3. 共享保护
- 共享页面的访问控制
- 确保共享数据的一致性
内存保护实现
硬件支持:
// MMU(内存管理单元)实现地址转换和保护
typedef struct {
int base_register; // 基址寄存器
int limit_register; // 界限寄存器
int protection_bits; // 保护位
} MMU;
软件支持:
// 操作系统内存管理
void memory_protection_check(int address, int access_type) {
if (!is_valid_address(address)) {
raise_segmentation_fault();
}
if (!has_permission(address, access_type)) {
raise_protection_fault();
}
}
内存管理的基本要求
1. 地址转换
- 将逻辑地址转换为物理地址
- 支持动态地址转换
- 高效的地址转换机制
2. 内存分配
- 为进程分配所需的内存空间
- 支持动态内存分配
- 高效的内存分配算法
3. 内存回收
- 及时回收不再使用的内存
- 防止内存泄漏
- 支持内存压缩
4. 内存保护
- 防止进程间相互干扰
- 保护系统内存不被破坏
- 支持内存访问权限控制
5. 内存共享
- 支持进程间内存共享
- 提高内存利用率
- 支持共享库
内存管理的发展历程
1. 单道程序设计
- 内存只分配给一个程序
- 简单的内存管理
- 内存利用率低
2. 多道程序设计
- 内存分配给多个程序
- 需要内存保护机制
- 支持程序切换
3. 分页系统
- 将内存划分为固定大小的页
- 支持虚拟内存
- 提高内存利用率
4. 分段系统
- 按逻辑模块分配内存
- 支持动态内存分配
- 便于程序模块化
5. 段页式系统
- 结合分段和分页的优点
- 支持复杂的地址空间
- 现代操作系统的主流方式
内存管理性能指标
1. 内存利用率
内存利用率 = 已使用内存 / 总内存 × 100%
2. 地址转换开销
- 页表访问次数
- TLB 命中率
- 地址转换延迟
3. 内存分配效率
- 分配算法的时间复杂度
- 内存碎片率
- 分配成功率
4. 内存保护开销
- 保护检查的时间开销
- 保护故障的频率
- 保护机制的可靠性
实际应用示例
Linux 内存管理
进程地址空间:
// 进程的虚拟地址空间布局
struct mm_struct {
unsigned long start_code; // 代码段起始地址
unsigned long end_code; // 代码段结束地址
unsigned long start_data; // 数据段起始地址
unsigned long end_data; // 数据段结束地址
unsigned long start_brk; // 堆起始地址
unsigned long brk; // 堆结束地址
unsigned long start_stack; // 栈起始地址
};
内存映射:
// 内存映射文件
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
Windows 内存管理
虚拟地址空间:
- 32 位系统:4GB 虚拟地址空间
- 64 位系统:16TB 虚拟地址空间
- 支持内存映射文件
内存保护:
- 页面级保护
- 段级保护
- 进程级保护
总结
内存管理基础是理解操作系统内存管理机制的关键。通过掌握程序装入与链接、地址空间转换和内存保护等基本概念,为学习更高级的内存管理技术奠定基础。现代操作系统的内存管理越来越复杂,但基本原理仍然是地址转换、内存分配、内存保护和内存共享。