百度网站推广方案网站开发重点难点分析
2026/3/1 6:58:52 网站建设 项目流程
百度网站推广方案,网站开发重点难点分析,微网站 pc网站同步,莱州网站建设包年正文大家好#xff01;今天给大家系统梳理《计算机操作系统》第五章 —— 虚拟存储器的核心知识点#xff0c;从基础概念到代码实现#xff0c;全程通俗易懂#xff0c;每个核心知识点都配有可直接运行的 C98 完整代码和可视化架构图 / 流程图#xff0c;方便大家动手实操…正文大家好今天给大家系统梳理《计算机操作系统》第五章 —— 虚拟存储器的核心知识点从基础概念到代码实现全程通俗易懂每个核心知识点都配有可直接运行的 C98 完整代码和可视化架构图 / 流程图方便大家动手实操彻底搞懂虚拟存储器5.1 虚拟存储器概述核心概念虚拟存储器Virtual Memory是操作系统中核心的内存管理技术简单来说用外存硬盘模拟内存让程序看起来拥有比实际物理内存更大的可用空间。它的核心目标是解决 “内存不足” 问题允许程序仅加载部分数据就运行实现进程的内存隔离提高系统安全性让程序编程时无需关心物理内存的实际大小。虚拟存储器核心架构核心特点离散性程序的内存空间离散分布在物理内存中多次性程序分多次加载到内存需要时才加载对换性内存中暂时不用的部分可换出到外存需要时再换入。5.2 请求分页存储管理方式请求分页是虚拟存储器最核心的实现方式是在 “基本分页” 基础上增加了缺页中断、页面置换两大核心机制。核心原理程序运行时只把当前需要的页面加载到物理内存当访问的页面不在内存时触发 “缺页中断”操作系统从外存加载该页面到内存若内存已满则调用 “页面置换算法” 淘汰部分页面。完整 C98 代码实现请求分页模拟#include iostream #include vector #include map #include cstdlib #include ctime // 兼容C98标准禁用C11及以上特性 using namespace std; // 页面状态枚举C98不支持强类型枚举用普通枚举 enum PageStatus { IN_MEMORY, // 在内存中 IN_DISK // 在磁盘中 }; // 页表项结构描述虚拟页的状态 struct PageTableEntry { int physical_frame; // 物理帧号-1表示不在内存 PageStatus status; // 页面状态 bool dirty; // 脏位是否被修改过 int access_count; // 访问次数用于置换算法 // 构造函数C98支持 PageTableEntry() : physical_frame(-1), status(IN_DISK), dirty(false), access_count(0) {} }; // 请求分页管理器类 class DemandPagingManager { private: vectorPageTableEntry page_table; // 页表虚拟页 - 物理帧映射 int total_physical_frames; // 物理内存总帧数内存大小 vectorbool physical_frames_used; // 物理帧使用状态true已占用 int disk_page_base; // 磁盘页面起始地址模拟外存 // 从磁盘加载页面到物理帧 void load_page_from_disk(int virtual_page, int physical_frame) { cout [缺页中断] 加载虚拟页 virtual_page 到物理帧 physical_frame endl; page_table[virtual_page].physical_frame physical_frame; page_table[virtual_page].status IN_MEMORY; page_table[virtual_page].access_count; physical_frames_used[physical_frame] true; // 模拟磁盘读取此处简化仅打印 cout 从磁盘地址 (disk_page_base virtual_page * 4096) 读取页面数据 endl; } // 寻找空闲物理帧返回-1表示无空闲 int find_free_frame() { for (int i 0; i total_physical_frames; i) { if (!physical_frames_used[i]) { return i; } } return -1; } // 简单置换算法淘汰访问次数最少的页面后续5.3会扩展 int replace_page() { int min_count 9999; int replace_frame -1; int replace_page -1; // 遍历页表找访问次数最少的页面 for (int i 0; i page_table.size(); i) { if (page_table[i].status IN_MEMORY page_table[i].access_count min_count) { min_count page_table[i].access_count; replace_frame page_table[i].physical_frame; replace_page i; } } // 淘汰页面写回磁盘如果是脏页 if (page_table[replace_page].dirty) { cout [置换] 虚拟页 replace_page 是脏页写回磁盘 endl; } cout [置换] 淘汰虚拟页 replace_page (物理帧 replace_frame ) endl; page_table[replace_page].status IN_DISK; page_table[replace_page].physical_frame -1; physical_frames_used[replace_frame] false; return replace_frame; } public: // 构造函数初始化页表、物理帧、磁盘地址 DemandPagingManager(int page_count, int frame_count) : total_physical_frames(frame_count) { // 初始化页表 page_table.resize(page_count); // 初始化物理帧使用状态 physical_frames_used.resize(frame_count, false); // 模拟磁盘页面起始地址4KB页大小 disk_page_base 0x10000000; // 随机数种子模拟页面访问 srand(time(NULL)); } // 访问指定虚拟页核心函数 void access_page(int virtual_page) { // 检查虚拟页是否合法 if (virtual_page 0 || virtual_page page_table.size()) { cout [错误] 虚拟页 virtual_page 超出范围 endl; return; } PageTableEntry entry page_table[virtual_page]; // 页面访问计数1 entry.access_count; // 情况1页面已在内存中 if (entry.status IN_MEMORY) { cout [命中] 虚拟页 virtual_page 命中物理帧 entry.physical_frame endl; return; } // 情况2页面不在内存触发缺页中断 int free_frame find_free_frame(); int target_frame; // 子情况2.1有空闲物理帧 if (free_frame ! -1) { target_frame free_frame; } // 子情况2.2无空闲物理帧需要置换 else { target_frame replace_page(); } // 加载页面到目标物理帧 load_page_from_disk(virtual_page, target_frame); } // 标记页面为脏页模拟页面修改 void modify_page(int virtual_page) { if (virtual_page 0 || virtual_page page_table.size()) { cout [错误] 虚拟页 virtual_page 超出范围 endl; return; } if (page_table[virtual_page].status IN_MEMORY) { page_table[virtual_page].dirty true; cout [修改] 虚拟页 virtual_page 标记为脏页 endl; } else { cout [错误] 虚拟页 virtual_page 不在内存无法修改 endl; } } // 打印当前页表状态 void print_page_table() { cout \n 当前页表状态 endl; cout 虚拟页\t物理帧\t状态\t脏位\t访问次数 endl; for (int i 0; i page_table.size(); i) { const PageTableEntry entry page_table[i]; cout i \t; if (entry.physical_frame -1) cout -; else cout entry.physical_frame; cout \t; cout (entry.status IN_MEMORY ? 内存 : 磁盘) \t; cout (entry.dirty ? 是 : 否) \t; cout entry.access_count endl; } cout \n endl; } }; // 主函数测试请求分页功能 int main() { // 初始化10个虚拟页4个物理帧模拟小内存场景 DemandPagingManager manager(10, 4); // 模拟页面访问序列随机访问模拟程序运行 int access_sequence[] {0, 1, 2, 3, 4, 1, 5, 2, 6, 0, 7, 3}; int seq_len sizeof(access_sequence) / sizeof(int); cout 开始模拟请求分页访问 endl; for (int i 0; i seq_len; i) { int page access_sequence[i]; cout \n第 (i1) 次访问虚拟页 page endl; manager.access_page(page); // 随机标记部分页面为脏页模拟写操作 if (rand() % 3 0) { manager.modify_page(page); } } // 打印最终页表状态 manager.print_page_table(); return 0; }代码说明C98 兼容要点禁用 C11 特性如nullptr改用-1、强类型枚举改用普通枚举、范围 for 循环改用普通 for核心逻辑模拟了 “缺页中断”、“空闲帧分配”、“简单页面置换” 三大核心流程可直接运行无需依赖第三方库g 编译时指定-stdc98即可。编译运行命令Linux/macOS# 编译指定C98标准 g -stdc98 demand_paging.cpp -o demand_paging # 运行 ./demand_paging5.3 页面置换算法页面置换算法是请求分页的核心决定了 “内存满时淘汰哪个页面”直接影响系统性能。常见置换算法对比算法名称核心思想优点缺点最佳置换OPT淘汰 “未来最久不使用” 的页面缺页率最低无法实现需要预知未来访问先进先出FIFO淘汰 “最先进入内存” 的页面简单易实现可能出现 “Belady 异常”内存越多缺页率越高最近最少使用LRU淘汰 “最近最久未使用” 的页面接近 OPT实用性强需要记录页面访问时间 / 次数时钟算法Clock基于 “使用位” 循环淘汰近似 LRU性能好开销低略逊于 LRULRU 置换算法完整 C98 实现替换 5.2 中的简单置换#include iostream #include vector #include map #include list #include cstdlib #include ctime using namespace std; // 页面状态枚举 enum PageStatus { IN_MEMORY, IN_DISK }; // 页表项结构增加访问时间戳 struct PageTableEntry { int physical_frame; PageStatus status; bool dirty; long long last_access_time; // 最后访问时间戳替代访问次数更精准 PageTableEntry() : physical_frame(-1), status(IN_DISK), dirty(false), last_access_time(0) {} }; // LRU页面置换管理器 class LRU_PagingManager { private: vectorPageTableEntry page_table; int total_physical_frames; vectorbool physical_frames_used; int disk_page_base; long long current_time; // 模拟系统时间戳 // 加载页面到物理帧 void load_page_from_disk(int virtual_page, int physical_frame) { cout [缺页中断] 加载虚拟页 virtual_page 到物理帧 physical_frame endl; page_table[virtual_page].physical_frame physical_frame; page_table[virtual_page].status IN_MEMORY; page_table[virtual_page].last_access_time current_time; physical_frames_used[physical_frame] true; } // 寻找空闲帧 int find_free_frame() { for (int i 0; i total_physical_frames; i) { if (!physical_frames_used[i]) { return i; } } return -1; } // LRU核心淘汰最近最久未使用的页面 int replace_page_LRU() { long long oldest_time current_time; int replace_frame -1; int replace_page -1; // 遍历页表找最后访问时间最早的页面 for (int i 0; i page_table.size(); i) { if (page_table[i].status IN_MEMORY page_table[i].last_access_time oldest_time) { oldest_time page_table[i].last_access_time; replace_frame page_table[i].physical_frame; replace_page i; } } // 淘汰页面 if (page_table[replace_page].dirty) { cout [LRU置换] 虚拟页 replace_page 写回磁盘 endl; } cout [LRU置换] 淘汰虚拟页 replace_page 最后访问时间 oldest_time endl; page_table[replace_page].status IN_DISK; page_table[replace_page].physical_frame -1; physical_frames_used[replace_frame] false; return replace_frame; } public: LRU_PagingManager(int page_count, int frame_count) : total_physical_frames(frame_count), current_time(0) { page_table.resize(page_count); physical_frames_used.resize(frame_count, false); disk_page_base 0x10000000; srand(time(NULL)); } // 访问页面更新时间戳 void access_page(int virtual_page) { if (virtual_page 0 || virtual_page page_table.size()) { cout [错误] 虚拟页 virtual_page 超出范围 endl; return; } PageTableEntry entry page_table[virtual_page]; current_time; // 时间戳递增 entry.last_access_time current_time; if (entry.status IN_MEMORY) { cout [命中] 虚拟页 virtual_page 命中物理帧 entry.physical_frame endl; return; } // 缺页中断处理 int free_frame find_free_frame(); int target_frame; if (free_frame ! -1) { target_frame free_frame; } else { target_frame replace_page_LRU(); } load_page_from_disk(virtual_page, target_frame); } // 标记脏页 void modify_page(int virtual_page) { if (virtual_page 0 || virtual_page page_table.size()) return; if (page_table[virtual_page].status IN_MEMORY) { page_table[virtual_page].dirty true; } } // 打印页表 void print_page_table() { cout \n LRU页表状态 endl; cout 虚拟页\t物理帧\t状态\t脏位\t最后访问时间 endl; for (int i 0; i page_table.size(); i) { const PageTableEntry entry page_table[i]; cout i \t; if (entry.physical_frame -1) cout -; else cout entry.physical_frame; cout \t; cout (entry.status IN_MEMORY ? 内存 : 磁盘) \t; cout (entry.dirty ? 是 : 否) \t; cout entry.last_access_time endl; } cout \n endl; } }; // 测试LRU算法 int main() { LRU_PagingManager lru_manager(10, 4); int access_sequence[] {0, 1, 2, 3, 4, 1, 5, 2, 6, 0, 7, 3}; int seq_len sizeof(access_sequence) / sizeof(int); cout LRU置换算法模拟 endl; for (int i 0; i seq_len; i) { int page access_sequence[i]; cout \n第 (i1) 次访问虚拟页 page endl; lru_manager.access_page(page); if (rand() % 3 0) { lru_manager.modify_page(page); } } lru_manager.print_page_table(); return 0; }LRU 算法流程图5.4 “抖动” 与工作集核心概念抖动Thrashing系统频繁发生缺页中断CPU 大部分时间都在处理 “调页 / 置换”而不是执行程序导致系统性能急剧下降。工作集Working Set进程在某段时间内频繁访问的页面集合简单说程序 “当前需要” 的页面。抖动产生原因 解决方法产生原因解决方法分配给进程的物理帧过少工作集无法全部装入内存增加进程的物理帧配额系统总内存不足多进程竞争内存减少并发进程数或增加物理内存页面置换算法选择不当使用 LRU/Clock 等高效置换算法工作集模拟C98 代码#include iostream #include vector #include set #include cstdlib #include ctime using namespace std; // 工作集管理器 class WorkingSetManager { private: vectorint access_history; // 页面访问历史 int window_size; // 工作集窗口大小最近N次访问 setint working_set; // 当前工作集去重 public: WorkingSetManager(int window) : window_size(window) {} // 记录页面访问并更新工作集 void record_access(int virtual_page) { // 添加到访问历史 access_history.push_back(virtual_page); // 保持历史长度不超过窗口大小 if (access_history.size() window_size) { access_history.erase(access_history.begin()); } // 更新工作集去重 working_set.clear(); for (vectorint::iterator it access_history.begin(); it ! access_history.end(); it) { working_set.insert(*it); } } // 打印当前工作集 void print_working_set() { cout 当前工作集窗口大小 window_size ; for (setint::iterator it working_set.begin(); it ! working_set.end(); it) { cout *it ; } cout 大小 working_set.size() endl; } // 检查是否发生抖动工作集大小 物理帧数 bool is_thrashing(int physical_frame_count) { return working_set.size() physical_frame_count; } }; // 测试工作集和抖动 int main() { WorkingSetManager ws_manager(5); // 窗口大小5 int physical_frames 3; // 物理帧数3 // 模拟页面访问序列故意制造抖动 int access_sequence[] {0, 1, 2, 3, 4, 0, 1, 5, 6, 7, 0, 2, 8}; int seq_len sizeof(access_sequence) / sizeof(int); cout 工作集 抖动模拟 endl; for (int i 0; i seq_len; i) { int page access_sequence[i]; cout \n第 (i1) 次访问虚拟页 page endl; ws_manager.record_access(page); ws_manager.print_working_set(); // 检查是否抖动 if (ws_manager.is_thrashing(physical_frames)) { cout [警告] 发生抖动工作集大小超过物理帧数 physical_frames endl; } } return 0; }5.5 请求分段存储管理方式请求分段是虚拟存储器的另一种实现方式与分页的核心区别是分段按 “逻辑功能” 划分如代码段、数据段页是固定大小的物理块。核心原理段的大小不固定按程序的逻辑结构划分运行时仅加载当前需要的段缺段时触发 “缺段中断”段表记录段的基址、长度、状态内存 / 外存等信息。请求分段完整 C98 代码实现#include iostream #include vector #include cstdlib #include ctime using namespace std; // 段状态枚举 enum SegmentStatus { IN_MEMORY, IN_DISK }; // 段表项结构 struct SegmentTableEntry { int base_address; // 段在内存中的基地址-1表示不在内存 int segment_length; // 段的长度字节 SegmentStatus status;// 段状态 bool dirty; // 脏位 SegmentTableEntry() : base_address(-1), segment_length(0), status(IN_DISK), dirty(false) {} SegmentTableEntry(int len) : base_address(-1), segment_length(len), status(IN_DISK), dirty(false) {} }; // 请求分段管理器 class DemandSegmentManager { private: vectorSegmentTableEntry segment_table; // 段表 int total_memory_size; // 物理内存总大小字节 vectorbool memory_used; // 内存使用位图模拟连续内存分配 int disk_segment_base; // 磁盘段起始地址 // 从磁盘加载段到内存模拟连续内存分配 int allocate_continuous_memory(int length) { // 找连续的空闲内存块首次适应算法 int free_start -1; int free_count 0; for (int i 0; i total_memory_size; i) { if (!memory_used[i]) { if (free_start -1) free_start i; free_count; if (free_count length) { // 分配内存 for (int j free_start; j free_start length; j) { memory_used[j] true; } return free_start; } } else { free_start -1; free_count 0; } } return -1; // 无足够连续内存 } // 释放段占用的内存 void free_memory(int base, int length) { for (int i base; i base length; i) { memory_used[i] false; } cout [释放内存] 段基址 base 长度 length endl; } // 从磁盘加载段 void load_segment_from_disk(int seg_num, int base) { cout [缺段中断] 加载段 seg_num 到内存基址 base endl; segment_table[seg_num].base_address base; segment_table[seg_num].status IN_MEMORY; // 模拟磁盘读取 cout 从磁盘地址 (disk_segment_base seg_num * 1024) 读取段数据 endl; } // 置换段简单置换释放最长的段 int replace_segment() { int max_length 0; int replace_seg -1; // 找内存中最长的段 for (int i 0; i segment_table.size(); i) { if (segment_table[i].status IN_MEMORY segment_table[i].segment_length max_length) { max_length segment_table[i].segment_length; replace_seg i; } } // 释放该段内存 int base segment_table[replace_seg].base_address; int len segment_table[replace_seg].segment_length; if (segment_table[replace_seg].dirty) { cout [置换] 段 replace_seg 是脏段写回磁盘 endl; } cout [置换] 淘汰段 replace_seg 长度 len endl; free_memory(base, len); segment_table[replace_seg].status IN_DISK; segment_table[replace_seg].base_address -1; // 分配新内存 return allocate_continuous_memory(len); } public: // 构造函数初始化段表、内存、磁盘 DemandSegmentManager(int seg_count, int mem_size) : total_memory_size(mem_size) { // 初始化段表随机生成段长度 segment_table.resize(seg_count); srand(time(NULL)); for (int i 0; i seg_count; i) { // 段长度100~500字节 int len 100 rand() % 401; segment_table[i] SegmentTableEntry(len); } // 初始化内存位图 memory_used.resize(mem_size, false); // 磁盘段起始地址 disk_segment_base 0x20000000; } // 访问段内地址核心函数 void access_segment(int seg_num, int offset) { // 检查段是否合法 if (seg_num 0 || seg_num segment_table.size()) { cout [错误] 段 seg_num 不存在 endl; return; } SegmentTableEntry entry segment_table[seg_num]; // 检查偏移量是否越界 if (offset entry.segment_length) { cout [错误] 段 seg_num 偏移量 offset 越界段长度 entry.segment_length endl; return; } // 段已在内存中 if (entry.status IN_MEMORY) { int physical_addr entry.base_address offset; cout [命中] 段 seg_num 命中物理地址 physical_addr endl; return; } // 段不在内存触发缺段中断 int required_len entry.segment_length; int base allocate_continuous_memory(required_len); // 无足够连续内存需要置换 if (base -1) { base replace_segment(); } // 加载段到内存 load_segment_from_disk(seg_num, base); int physical_addr base offset; cout [访问] 段 seg_num 物理地址 physical_addr endl; } // 标记段为脏段 void modify_segment(int seg_num) { if (seg_num 0 || seg_num segment_table.size()) return; if (segment_table[seg_num].status IN_MEMORY) { segment_table[seg_num].dirty true; cout [修改] 段 seg_num 标记为脏段 endl; } } // 打印段表 void print_segment_table() { cout \n 当前段表状态 endl; cout 段号\t基地址\t长度\t状态\t脏位 endl; for (int i 0; i segment_table.size(); i) { const SegmentTableEntry entry segment_table[i]; cout i \t; if (entry.base_address -1) cout -; else cout entry.base_address; cout \t entry.segment_length \t; cout (entry.status IN_MEMORY ? 内存 : 磁盘) \t; cout (entry.dirty ? 是 : 否) endl; } cout \n endl; } }; // 主函数测试 int main() { // 初始化5个段物理内存大小2000字节 DemandSegmentManager seg_manager(5, 2000); // 模拟段访问序列 int access_sequence[][2] {{0, 50}, {1, 80}, {2, 100}, {3, 150}, {4, 200}, {0, 60}, {2, 90}}; int seq_len sizeof(access_sequence) / sizeof(access_sequence[0]); cout 开始模拟请求分段访问 endl; for (int i 0; i seq_len; i) { int seg_num access_sequence[i][0]; int offset access_sequence[i][1]; cout \n第 (i1) 次访问段 seg_num 偏移量 offset endl; seg_manager.access_segment(seg_num, offset); if (rand() % 2 0) { seg_manager.modify_segment(seg_num); } } seg_manager.print_segment_table(); return 0; }请求分段 vs 请求分页 核心区别思维导图习题基础题简述虚拟存储器的核心特征为什么需要虚拟存储器缺页中断与普通中断有何区别什么是 Belady 异常哪些置换算法会出现该异常抖动的产生原因是什么如何避免抖动对比请求分页和请求分段的优缺点分别适用于什么场景编程题基于本文的 LRU 代码实现 Clock时钟置换算法扩展请求分页代码统计 “缺页率”缺页次数 / 总访问次数模拟多个进程共享物理内存实现进程间的内存隔离。总结虚拟存储器的核心是 “部分加载、按需调页 / 调段”解决了物理内存不足的问题核心依赖缺页 / 缺段中断和页面置换算法请求分页是主流实现方式LRU 是最常用的置换算法接近最优需避免 “抖动”工作集超出物理内存请求分段按逻辑功能划分适合共享 / 保护但存在外部碎片问题分页无外部碎片但逻辑性弱。最后所有代码均基于 C98 标准编写可直接编译运行大家可以动手修改参数如物理帧数、访问序列、窗口大小观察不同场景下的运行结果加深对虚拟存储器的理解如果有问题欢迎评论区交流

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询