前言
大家好!今天给大家带来《计算机操作系统》第四章 ------ 存储器管理的全面解析。存储器管理是操作系统核心模块之一,直接决定了程序能否高效、安全地运行。本文会从基础概念到代码实现,用通俗易懂的语言拆解每个知识点,还会附上可直接运行的 C++代码,帮助大家彻底吃透这一章!
4.1 存储器的层次结构
核心概念
存储器的层次结构是为了解决「速度快的存储器贵、容量小,容量大的存储器速度慢、便宜」的矛盾,操作系统通过分层管理让 CPU 既能快速访问数据,又能使用大容量存储。
层次架构

核心要点
- 越靠近 CPU 的存储层级,速度越快、容量越小、单位成本越高;
- 操作系统的存储器管理主要针对主存储器(内存) ,虚拟存储器是内存 + 外存的抽象层;
- 层次结构的核心目标:用低成本实现接近高速缓存的访问速度、接近硬盘的存储容量。
4.2 程序的装入和链接
核心概念
程序从「磁盘上的可执行文件」到「内存中运行的进程」,需要经过装入 (Load)和链接(Link)两个核心步骤:
- 链接:将多个目标文件、库文件合并为一个可执行文件(静态链接 / 动态链接);
- 装入:将可执行文件加载到内存,分配地址空间(绝对装入 / 可重定位装入 / 动态运行时装入)。
装入流程

代码实现(C++98 模拟程序装入过程)
cpp
#include <iostream>
#include <vector>
#include <string>
// 严格兼容C++98标准,无任何C++11特性
using namespace std;
// 定义目标文件结构体
struct ObjectFile {
string name; // 目标文件名
vector<int> code; // 机器码(简化为整数数组)
vector<int> data; // 数据段(简化为整数数组)
};
// 定义可执行文件结构体
struct ExecFile {
string name; // 可执行文件名
vector<int> text_segment; // 代码段
vector<int> data_segment; // 数据段
int base_addr; // 装入的基地址
};
// 静态链接:合并多个目标文件为可执行文件(C++98兼容版)
ExecFile static_link(const vector<ObjectFile>& objs, const string& exec_name) {
ExecFile exec;
exec.name = exec_name;
exec.base_addr = 0; // 初始基地址为0
// C++98不支持范围for循环,改用下标循环
for (size_t i = 0; i < objs.size(); ++i) {
const ObjectFile& obj = objs[i];
// 合并代码段
exec.text_segment.insert(exec.text_segment.end(), obj.code.begin(), obj.code.end());
// 合并数据段
exec.data_segment.insert(exec.data_segment.end(), obj.data.begin(), obj.data.end());
}
return exec;
}
// 可重定位装入:将可执行文件加载到指定内存地址
void relocate_load(ExecFile& exec, int new_base_addr) {
exec.base_addr = new_base_addr;
cout << "可执行文件[" << exec.name << "]装入内存,基地址:" << new_base_addr << endl;
// 模拟地址重定位:代码段地址 = 基地址 + 偏移量
cout << "代码段地址重定位结果:" << endl;
for (size_t i = 0; i < exec.text_segment.size(); ++i) {
int old_addr = exec.text_segment[i];
exec.text_segment[i] = new_base_addr + static_cast<int>(i); // 偏移量为索引
cout << " 原地址:" << old_addr << " → 新地址:" << exec.text_segment[i] << endl;
}
}
int main() {
// 1. 模拟编译生成目标文件(C++98兼容:用push_back初始化vector)
ObjectFile obj1, obj2;
obj1.name = "main.o";
// 替代列表初始化:逐个添加元素
obj1.code.push_back(1001);
obj1.code.push_back(1002);
obj1.code.push_back(1003);
obj1.data.push_back(10);
obj1.data.push_back(20);
obj1.data.push_back(30);
obj2.name = "utils.o";
obj2.code.push_back(2001);
obj2.code.push_back(2002);
obj2.data.push_back(40);
obj2.data.push_back(50);
// 2. 静态链接
vector<ObjectFile> objs;
objs.push_back(obj1);
objs.push_back(obj2);
ExecFile exec = static_link(objs, "app.exe");
cout << "静态链接完成,生成可执行文件:" << exec.name << endl;
// 3. 可重定位装入(基地址设为0x1000)
relocate_load(exec, 0x1000);
return 0;
}

代码说明
- 用
ObjectFile模拟编译后的目标文件,包含代码段和数据段; static_link函数模拟静态链接,合并多个目标文件的段;relocate_load函数模拟可重定位装入,将可执行文件加载到指定基地址并完成地址重定位;- 代码完全兼容 C++98 标准,可直接编译运行(g++ 编译命令:
g++ -std=c++98 load_link.cpp -o load_link)。
运行结果
4.3 连续分配存储管理方式
核心概念
连续分配是最基础的内存管理方式,要求给进程分配连续的内存空间,主要分为:
- 单一连续分配:内存分为系统区和用户区,仅支持单进程(早期 OS);
- 固定分区分配:将内存划分为多个固定大小的分区,每个分区装一个进程;
- 动态分区分配:根据进程大小动态划分连续内存(首次适应 / 最佳适应 / 最坏适应算法)。
动态分区分配流程

代码实现(C++98 模拟动态分区分配)
cpp
#include <iostream>
#include <vector>
#include <string>
#include <climits>
#include <algorithm> // sort函数必需的头文件
// 严格遵循C++98标准
using namespace std;
// 定义空闲分区结构体
struct FreeBlock {
int start_addr; // 分区起始地址
int size; // 分区大小
FreeBlock(int s, int sz) : start_addr(s), size(sz) {}
};
// ========== 关键修改:将比较结构体移到全局作用域 ==========
// C++98不允许函数内局部类型作为sort的模板参数
struct CompareBlock {
bool operator()(const FreeBlock& a, const FreeBlock& b) {
return a.start_addr < b.start_addr;
}
};
// 定义进程结构体
struct Process {
string pid; // 进程ID
int size; // 所需内存大小
int alloc_addr; // 分配的起始地址
Process(string p, int sz) : pid(p), size(sz), alloc_addr(-1) {}
};
// 空闲分区表(全局)
vector<FreeBlock> free_blocks;
// 首次适应算法:找第一个足够大的空闲分区
int first_fit(int req_size) {
// 显式转换size_t为int,避免无符号/有符号比较警告
for (int i = 0; i < static_cast<int>(free_blocks.size()); ++i) {
if (free_blocks[i].size >= req_size) {
return i; // 返回分区索引
}
}
return -1; // 无可用分区
}
// 最佳适应算法:找最小的足够大的空闲分区
int best_fit(int req_size) {
int best_idx = -1;
int min_size = INT_MAX;
// 显式转换size_t为int,避免警告
for (int i = 0; i < static_cast<int>(free_blocks.size()); ++i) {
if (free_blocks[i].size >= req_size && free_blocks[i].size < min_size) {
min_size = free_blocks[i].size;
best_idx = i;
}
}
return best_idx;
}
// 分配内存
bool allocate_memory(Process& p, int algo_type) {
int idx = -1;
// 0=首次适应,1=最佳适应
if (algo_type == 0) {
idx = first_fit(p.size);
} else if (algo_type == 1) {
idx = best_fit(p.size);
}
if (idx == -1) {
cout << "进程[" << p.pid << "]分配内存失败:无足够空闲分区" << endl;
return false;
}
// 分配内存
FreeBlock& block = free_blocks[idx];
p.alloc_addr = block.start_addr;
cout << "进程[" << p.pid << "]分配成功:起始地址=" << block.start_addr
<< ",大小=" << p.size << endl;
// 更新空闲分区表(分割分区)
if (block.size > p.size) {
// 剩余空间形成新的空闲分区
free_blocks.push_back(FreeBlock(block.start_addr + p.size, block.size - p.size));
}
// 删除已分配的分区
free_blocks.erase(free_blocks.begin() + idx);
return true;
}
// 释放内存并合并相邻空闲分区
void free_memory(Process& p) {
if (p.alloc_addr == -1) {
cout << "进程[" << p.pid << "]未分配内存,无需释放" << endl;
return;
}
// 添加释放的分区到空闲表
free_blocks.push_back(FreeBlock(p.alloc_addr, p.size));
cout << "进程[" << p.pid << "]释放内存:起始地址=" << p.alloc_addr
<< ",大小=" << p.size << endl;
p.alloc_addr = -1;
// 合并相邻空闲分区(简化版:按起始地址排序后合并)
// ========== 关键修改:使用全局的CompareBlock ==========
sort(free_blocks.begin(), free_blocks.end(), CompareBlock());
// 合并逻辑
// 显式转换size_t为int,避免循环条件警告
for (int i = 0; i < static_cast<int>(free_blocks.size()) - 1; ) {
FreeBlock& curr = free_blocks[i];
FreeBlock& next = free_blocks[i+1];
if (curr.start_addr + curr.size == next.start_addr) {
// 合并两个分区
curr.size += next.size;
free_blocks.erase(free_blocks.begin() + i + 1);
} else {
i++;
}
}
// 打印合并后的空闲分区表
cout << "合并后空闲分区表:" << endl;
for (size_t i = 0; i < free_blocks.size(); ++i) {
cout << " 分区" << i+1 << ":起始地址=" << free_blocks[i].start_addr
<< ",大小=" << free_blocks[i].size << endl;
}
}
// 打印空闲分区表
void print_free_blocks() {
cout << "当前空闲分区表:" << endl;
for (size_t i = 0; i < free_blocks.size(); ++i) {
cout << " 分区" << i+1 << ":起始地址=" << free_blocks[i].start_addr
<< ",大小=" << free_blocks[i].size << endl;
}
}
int main() {
// 初始化空闲分区:总内存0~1000,初始为一个大分区
free_blocks.push_back(FreeBlock(0, 1000));
cout << "初始空闲分区表:" << endl;
print_free_blocks();
// 创建进程
Process p1("P1", 200);
Process p2("P2", 300);
Process p3("P3", 400);
// 首次适应算法分配P1
cout << "\n--- 首次适应分配P1(200)---" << endl;
allocate_memory(p1, 0);
print_free_blocks();
// 最佳适应算法分配P2
cout << "\n--- 最佳适应分配P2(300)---" << endl;
allocate_memory(p2, 1);
print_free_blocks();
// 释放P1
cout << "\n--- 释放P1 ---" << endl;
free_memory(p1);
// 最佳适应算法分配P3
cout << "\n--- 最佳适应分配P3(400)---" << endl;
allocate_memory(p3, 1);
print_free_blocks();
return 0;
}
代码说明
FreeBlock模拟空闲分区,Process模拟进程;- 实现了首次适应 和最佳适应两种核心分配算法;
- 释放内存时自动合并相邻空闲分区(解决内存碎片问题);
- 代码兼容 C++98:使用
vector、自定义排序比较函数(C++98 不支持 lambda)、INT_MAX等; - 编译命令:
g++ -std=c++98 continuous_alloc.cpp -o continuous_alloc。
运行结果
4.4 对换 (Swapping)
核心概念
对换(也叫交换)是解决内存不足的核心技术:
- 内存紧张时,将暂时不运行的进程完整换出到外存(交换区),释放内存;
- 需要运行时,再将进程换入到内存;
- 核心目标:提高内存利用率,支持更多进程并发。
对换流程

代码实现(C++98 模拟对换机制)
cpp
#include <iostream>
#include <vector>
#include <string>
#include <queue>
// 严格C++98标准
using namespace std;
// 进程状态枚举(C++98不支持enum class,用普通枚举)
enum ProcessState {
RUNNING, // 内存中运行
WAITING, // 等待换入
SWAPPED // 换出到外存
};
// 进程结构体
struct Process {
string pid; // 进程ID
int size; // 内存大小
int priority; // 优先级(数值越小优先级越高)
int run_time; // 已运行时间
ProcessState state; // 状态
Process(string p, int sz, int pri) : pid(p), size(sz), priority(pri), run_time(0), state(WAITING) {}
};
// 内存结构体
struct Memory {
int total_size; // 总大小
int used_size; // 已用大小
vector<Process*> running_procs; // 内存中的进程
Memory(int sz) : total_size(sz), used_size(0) {}
};
// 外存交换区
struct SwapArea {
int total_size; // 总大小
int used_size; // 已用大小
vector<Process*> swapped_procs; // 换出的进程
SwapArea(int sz) : total_size(sz), used_size(0) {}
};
// 选择换出进程(按优先级:优先级低的先换出;优先级相同则运行时间长的先换出)
Process* select_swap_out_proc(Memory& mem) {
Process* swap_proc = NULL;
int max_priority = -1;
int max_run_time = -1;
// ========== 修复:替换C++11范围for为C++98迭代器循环 ==========
for (vector<Process*>::iterator it = mem.running_procs.begin(); it != mem.running_procs.end(); ++it) {
Process* p = *it;
if (p->priority > max_priority || (p->priority == max_priority && p->run_time > max_run_time)) {
max_priority = p->priority;
max_run_time = p->run_time;
swap_proc = p;
}
}
return swap_proc;
}
// 换出进程到外存
bool swap_out(Memory& mem, SwapArea& swap, Process* p) {
if (swap.used_size + p->size > swap.total_size) {
cout << "交换区空间不足,换出进程[" << p->pid << "]失败" << endl;
return false;
}
// 从内存移除
for (vector<Process*>::iterator it = mem.running_procs.begin(); it != mem.running_procs.end(); ++it) {
if ((*it)->pid == p->pid) {
mem.running_procs.erase(it);
break;
}
}
mem.used_size -= p->size;
p->state = SWAPPED;
// 加入交换区
swap.swapped_procs.push_back(p);
swap.used_size += p->size;
cout << "进程[" << p->pid << "]换出成功!内存释放:" << p->size << ",交换区占用:" << swap.used_size << endl;
return true;
}
// 换入进程到内存
bool swap_in(Memory& mem, SwapArea& swap, Process* p) {
if (mem.used_size + p->size > mem.total_size) {
// 内存不足,先换出一个进程
Process* swap_out_proc = select_swap_out_proc(mem);
if (swap_out_proc == NULL) {
cout << "无可用进程换出,换入进程[" << p->pid << "]失败" << endl;
return false;
}
if (!swap_out(mem, swap, swap_out_proc)) {
return false;
}
}
// 从交换区移除
for (vector<Process*>::iterator it = swap.swapped_procs.begin(); it != swap.swapped_procs.end(); ++it) {
if ((*it)->pid == p->pid) {
swap.swapped_procs.erase(it);
break;
}
}
swap.used_size -= p->size;
p->state = RUNNING;
// 加入内存
mem.running_procs.push_back(p);
mem.used_size += p->size;
cout << "进程[" << p->pid << "]换入成功!内存占用:" << mem.used_size << endl;
return true;
}
// 打印系统状态
void print_system_state(Memory& mem, SwapArea& swap) {
cout << "\n=== 系统状态 ===" << endl;
cout << "内存:总大小=" << mem.total_size << ",已用=" << mem.used_size << endl;
cout << " 运行中进程:";
// ========== 修复:替换C++11范围for为C++98迭代器循环 ==========
for (vector<Process*>::iterator it = mem.running_procs.begin(); it != mem.running_procs.end(); ++it) {
Process* p = *it;
cout << p->pid << "(" << p->size << ") ";
}
cout << endl;
cout << "交换区:总大小=" << swap.total_size << ",已用=" << swap.used_size << endl;
cout << " 换出进程:";
// ========== 修复:替换C++11范围for为C++98迭代器循环 ==========
for (vector<Process*>::iterator it = swap.swapped_procs.begin(); it != swap.swapped_procs.end(); ++it) {
Process* p = *it;
cout << p->pid << "(" << p->size << ") ";
}
cout << "\n=================\n" << endl;
}
int main() {
// 初始化内存(总大小1000)和交换区(总大小2000)
Memory mem(1000);
SwapArea swap(2000);
// 创建进程
Process p1("P1", 300, 1); // 高优先级
Process p2("P2", 400, 2); // 中优先级
Process p3("P3", 500, 3); // 低优先级
// 换入P1
cout << "--- 换入P1(300)---" << endl;
swap_in(mem, swap, &p1);
print_system_state(mem, swap);
// 换入P2
cout << "--- 换入P2(400)---" << endl;
swap_in(mem, swap, &p2);
print_system_state(mem, swap);
// 换入P3(内存不足,触发换出)
cout << "--- 换入P3(500)---" << endl;
p2.run_time = 10; // P2运行时间长,优先换出
swap_in(mem, swap, &p3);
print_system_state(mem, swap);
// 换入P2
cout << "--- 换入P2(400)---" << endl;
swap_in(mem, swap, &p2);
print_system_state(mem, swap);
return 0;
}
代码说明
- 定义
Process结构体,包含优先级、运行时间、状态等核心属性; Memory模拟内存,SwapArea模拟外存交换区;swap_out实现进程换出,swap_in实现进程换入(内存不足时自动触发换出);- 换出策略:优先换出优先级低、运行时间长的进程;
- 编译命令:
g++ -std=c++98 swapping.cpp -o swapping。
运行结果
4.5 分页存储管理方式
核心概念
分页是解决连续分配「内存碎片」问题的核心方案:
- 内存划分为固定大小的页框(Page Frame)(如 4KB);
- 进程地址空间划分为大小相同的页(Page);
- 进程的页可以离散分配到内存的页框中,通过页表映射页和页框的对应关系;
- 核心优势:无外部碎片,仅少量内部碎片(最后一页未占满的部分)。
分页架构

代码实现(C++98 模拟分页存储管理)
#include <iostream>
#include <vector>
#include <string>
#include <map>
// C++98标准
using namespace std;
// 页大小(固定为4KB)
const int PAGE_SIZE = 4096;
// 页表项结构体
struct PageTableEntry {
int frame_num; // 页框号
bool valid; // 有效位(是否在内存中)
PageTableEntry() : frame_num(-1), valid(false) {}
};
// 进程结构体
struct Process {
string pid; // 进程ID
int size; // 进程大小
vector<PageTableEntry> pt; // 页表
Process(string p, int sz) : pid(p), size(sz) {
// 计算页数:向上取整
int page_count = (sz + PAGE_SIZE - 1) / PAGE_SIZE;
pt.resize(page_count); // 初始化页表
}
};
// 内存页框管理器
struct FrameManager {
int total_frames; // 总页框数
vector<bool> frame_used; // 页框使用状态(true=已用)
FrameManager(int total_size) : total_frames(total_size / PAGE_SIZE) {
frame_used.resize(total_frames, false); // 初始全空闲
}
// 分配空闲页框
int allocate_frame() {
for (int i = 0; i < total_frames; ++i) {
if (!frame_used[i]) {
frame_used[i] = true;
return i;
}
}
return -1; // 无空闲页框
}
// 释放页框
void free_frame(int frame_num) {
if (frame_num >= 0 && frame_num < total_frames) {
frame_used[frame_num] = false;
cout << "页框" << frame_num << "释放成功" << endl;
}
}
// 打印页框使用状态
void print_frames() {
cout << "页框使用状态(总" << total_frames << "个):";
for (int i = 0; i < total_frames; ++i) {
cout << (frame_used[i] ? "1" : "0");
}
cout << endl;
}
};
// 虚拟地址转物理地址
int virtual_to_physical(Process& p, int virtual_addr) {
// 拆分虚拟地址:页号 = 虚拟地址 / 页大小,页内偏移 = 虚拟地址 % 页大小
int page_num = virtual_addr / PAGE_SIZE;
int offset = virtual_addr % PAGE_SIZE;
// 检查页号是否合法
if (page_num >= (int)p.pt.size()) {
cout << "进程[" << p.pid << "]虚拟地址" << virtual_addr << ":页号" << page_num << "越界" << endl;
return -1;
}
// 检查有效位
PageTableEntry& pte = p.pt[page_num];
if (!pte.valid) {
cout << "进程[" << p.pid << "]虚拟地址" << virtual_addr << ":页" << page_num << "不在内存中(缺页)" << endl;
return -1;
}
// 计算物理地址 = 页框号 * 页大小 + 页内偏移
int physical_addr = pte.frame_num * PAGE_SIZE + offset;
cout << "进程[" << p.pid << "]虚拟地址" << virtual_addr
<< " → 页号" << page_num << ",偏移" << offset
<< " → 物理地址" << physical_addr << endl;
return physical_addr;
}
// 分配进程的页到内存页框
bool allocate_pages(Process& p, FrameManager& fm) {
cout << "为进程[" << p.pid << "]分配页(总页数:" << p.pt.size() << ")" << endl;
for (int i = 0; i < (int)p.pt.size(); ++i) {
int frame = fm.allocate_frame();
if (frame == -1) {
cout << "页框不足,进程[" << p.pid << "]分配失败" << endl;
// 回滚已分配的页框
for (int j = 0; j < i; ++j) {
fm.free_frame(p.pt[j].frame_num);
p.pt[j].valid = false;
}
return false;
}
p.pt[i].frame_num = frame;
p.pt[i].valid = true;
cout << " 页" << i << " → 页框" << frame << endl;
}
return true;
}
int main() {
// 初始化内存:总大小32KB → 8个页框(4KB/页)
FrameManager fm(32 * 1024);
cout << "初始页框状态:" << endl;
fm.print_frames();
// 创建进程:大小10KB → 需要3页(4+4+2)
Process p1("P1", 10 * 1024);
// 分配页
cout << "\n--- 分配P1的页 ---" << endl;
allocate_pages(p1, fm);
fm.print_frames();
// 虚拟地址转物理地址
cout << "\n--- 虚拟地址转换 ---" << endl;
virtual_to_physical(p1, 1000); // 页0,偏移1000
virtual_to_physical(p1, 5000); // 页1,偏移904
virtual_to_physical(p1, 9000); // 页2,偏移808
virtual_to_physical(p1, 13000); // 页3,越界
// 释放进程的页框
cout << "\n--- 释放P1的页框 ---" << endl;
for (int i = 0; i < (int)p1.pt.size(); ++i) {
fm.free_frame(p1.pt[i].frame_num);
p1.pt[i].valid = false;
}
fm.print_frames();
return 0;
}
代码说明
- 固定页大小为 4KB,
FrameManager管理内存页框的分配 / 释放; Process包含页表,页表项记录页框号和有效位;virtual_to_physical实现虚拟地址到物理地址的转换(核心逻辑);- 模拟「缺页」「地址越界」等异常场景;
- 编译命令:
g++ -std=c++98 paging.cpp -o paging。
运行结果
4.6 分段存储管理方式
核心概念
分段是按程序的逻辑结构划分内存(如代码段、数据段、栈段),每个段是连续的内存块,不同段可离散分配:
- 段:有意义的逻辑单位,大小不固定(如代码段 10KB、栈段 5KB);
- 段表:记录每个段的基地址和段长,实现虚拟地址到物理地址的映射;
- 核心优势:便于程序的共享和保护(如代码段只读、数据段可读写)。
分段架构

代码实现(C++98 模拟分段存储管理)
#include <iostream>
#include <vector>
#include <string>
#include <map>
// C++98标准
using namespace std;
// 段表项结构体
struct SegmentTableEntry {
string seg_name; // 段名(代码段/数据段/栈段)
int base_addr; // 段基地址
int seg_size; // 段长度
string protect; // 保护属性(R-只读,RW-读写,X-执行)
bool valid; // 有效位
SegmentTableEntry(string name, int size, string prot) : seg_name(name), seg_size(size), protect(prot), base_addr(-1), valid(false) {}
};
// 进程结构体
struct Process {
string pid; // 进程ID
vector<SegmentTableEntry> seg_table; // 段表
Process(string p) : pid(p) {}
// 添加段
void add_segment(string name, int size, string protect) {
seg_table.push_back(SegmentTableEntry(name, size, protect));
}
};
// 内存管理器
struct MemoryManager {
int total_size; // 总内存大小
int used_size; // 已用大小
MemoryManager(int sz) : total_size(sz), used_size(0) {}
// 分配连续内存段
int allocate_segment(int size) {
if (used_size + size > total_size) {
return -1; // 内存不足
}
int base = used_size;
used_size += size;
return base;
}
// 释放段(简化版:不合并,仅标记内存可用)
void free_segment(int base, int size) {
cout << "释放段:基地址=" << base << ",大小=" << size << endl;
// 实际OS中需要管理空闲分区,此处简化为打印
used_size -= size;
}
};
// 虚拟地址转物理地址
int virtual_to_physical(Process& p, MemoryManager& mm, int seg_num, int offset) {
// 检查段号是否合法
if (seg_num >= (int)p.seg_table.size()) {
cout << "进程[" << p.pid << "]段号" << seg_num << "越界" << endl;
return -1;
}
SegmentTableEntry& ste = p.seg_table[seg_num];
// 检查有效位
if (!ste.valid) {
cout << "进程[" << p.pid << "]段" << ste.seg_name << "不在内存中" << endl;
return -1;
}
// 检查段内偏移是否越界
if (offset >= ste.seg_size) {
cout << "进程[" << p.pid << "]段" << ste.seg_name << "内偏移" << offset << "越界(段长:" << ste.seg_size << ")" << endl;
return -1;
}
// 计算物理地址
int physical_addr = ste.base_addr + offset;
cout << "进程[" << p.pid << "]段" << ste.seg_name << "(段号" << seg_num << ")偏移" << offset
<< " → 物理地址" << physical_addr << "(保护属性:" << ste.protect << ")" << endl;
return physical_addr;
}
// 分配进程的段到内存
bool allocate_segments(Process& p, MemoryManager& mm) {
cout << "为进程[" << p.pid << "]分配段:" << endl;
for (int i = 0; i < (int)p.seg_table.size(); ++i) {
SegmentTableEntry& ste = p.seg_table[i];
int base = mm.allocate_segment(ste.seg_size);
if (base == -1) {
cout << "内存不足,进程[" << p.pid << "]段" << ste.seg_name << "分配失败" << endl;
// 回滚已分配的段
for (int j = 0; j < i; ++j) {
mm.free_segment(p.seg_table[j].base_addr, p.seg_table[j].seg_size);
p.seg_table[j].valid = false;
}
return false;
}
ste.base_addr = base;
ste.valid = true;
cout << " 段" << i << "(" << ste.seg_name << "):基地址=" << base << ",大小=" << ste.seg_size << endl;
}
return true;
}
int main() {
// 初始化内存(总大小20KB)
MemoryManager mm(20 * 1024);
cout << "初始内存:总大小=" << mm.total_size << ",已用=" << mm.used_size << endl;
// 创建进程并添加段
Process p1("P1");
p1.add_segment("代码段", 5 * 1024, "X"); // 执行权限
p1.add_segment("数据段", 8 * 1024, "RW"); // 读写权限
p1.add_segment("栈段", 3 * 1024, "RW"); // 读写权限
// 分配段
cout << "\n--- 分配P1的段 ---" << endl;
allocate_segments(p1, mm);
cout << "分配后内存:已用=" << mm.used_size << endl;
// 虚拟地址转物理地址
cout << "\n--- 虚拟地址转换 ---" << endl;
virtual_to_physical(p1, mm, 0, 1000); // 代码段,偏移1000
virtual_to_physical(p1, mm, 1, 2000); // 数据段,偏移2000
virtual_to_physical(p1, mm, 2, 4000); // 栈段,偏移4000(越界)
virtual_to_physical(p1, mm, 3, 1000); // 段号3(越界)
return 0;
}
代码说明
SegmentTableEntry包含段名、基地址、段长、保护属性等核心字段;MemoryManager管理连续内存段的分配 / 释放;virtual_to_physical实现分段地址转换,包含越界检查 和保护属性校验;- 模拟代码段(执行权限)、数据段 / 栈段(读写权限)的不同保护策略;
- 编译命令:
g++ -std=c++98 segmentation.cpp -o segmentation。
运行结果
习题
基础题
- 简述存储器层次结构的设计思想,为什么需要分层管理?
- 对比连续分配、分页、分段三种存储管理方式的优缺点。
- 分页和分段的核心区别是什么?(提示:页是物理划分,段是逻辑划分)
- 对换技术的核心作用是什么?换出进程的选择策略有哪些?
编程题
- 基于本文的分页代码,实现「最坏适应算法」的页框分配策略。
- 基于本文的分段代码,添加「段共享」功能(多个进程共享同一个代码段)。
- 扩展对换代码,实现「按进程剩余运行时间」选择换出进程的策略。
总结
核心知识点回顾
- 存储器层次结构:核心是「速度 - 容量 - 成本」的平衡,OS 主要管理主存,虚拟内存是内存 + 外存的抽象;
- 存储管理方式 :
- 连续分配:简单但有外部碎片,适合早期单进程 OS;
- 分页:离散分配,无外部碎片,按物理大小划分;
- 分段:离散分配,按逻辑结构划分,便于共享和保护;
- 核心技术:程序装入链接是进程运行的前提,对换技术解决内存不足问题,地址转换(分页 / 分段)是虚拟地址到物理地址的核心。




