news 2026/4/2 19:31:12

《计算机操作系统》第五章-虚拟存储器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《计算机操作系统》第五章-虚拟存储器

正文

大家好!今天给大家系统梳理《计算机操作系统》第五章 —— 虚拟存储器的核心知识点,从基础概念到代码实现,全程通俗易懂,每个核心知识点都配有可直接运行的 C++98 完整代码和可视化架构图 / 流程图,方便大家动手实操,彻底搞懂虚拟存储器!

5.1 虚拟存储器概述

核心概念

虚拟存储器(Virtual Memory)是操作系统中核心的内存管理技术,简单来说:用外存(硬盘)模拟内存,让程序看起来拥有比实际物理内存更大的可用空间

它的核心目标是:

  1. 解决 “内存不足” 问题,允许程序仅加载部分数据就运行;
  2. 实现进程的内存隔离,提高系统安全性;
  3. 让程序编程时无需关心物理内存的实际大小。
虚拟存储器核心架构

核心特点
  • 离散性:程序的内存空间离散分布在物理内存中;
  • 多次性:程序分多次加载到内存(需要时才加载);
  • 对换性:内存中暂时不用的部分可换出到外存,需要时再换入。

5.2 请求分页存储管理方式

请求分页是虚拟存储器最核心的实现方式,是在 “基本分页” 基础上增加了缺页中断页面置换两大核心机制。

核心原理
  1. 程序运行时,只把当前需要的页面加载到物理内存;
  2. 当访问的页面不在内存时,触发 “缺页中断”;
  3. 操作系统从外存加载该页面到内存,若内存已满则调用 “页面置换算法” 淘汰部分页面。
完整 C++98 代码实现(请求分页模拟)
#include <iostream> #include <vector> #include <map> #include <cstdlib> #include <ctime> // 兼容C++98标准,禁用C++11及以上特性 using namespace std; // 页面状态枚举(C++98不支持强类型枚举,用普通枚举) enum PageStatus { IN_MEMORY, // 在内存中 IN_DISK // 在磁盘中 }; // 页表项结构(描述虚拟页的状态) struct PageTableEntry { int physical_frame; // 物理帧号(-1表示不在内存) PageStatus status; // 页面状态 bool dirty; // 脏位(是否被修改过) int access_count; // 访问次数(用于置换算法) // 构造函数(C++98支持) PageTableEntry() : physical_frame(-1), status(IN_DISK), dirty(false), access_count(0) {} }; // 请求分页管理器类 class DemandPagingManager { private: vector<PageTableEntry> page_table; // 页表(虚拟页 -> 物理帧映射) int total_physical_frames; // 物理内存总帧数(内存大小) vector<bool> 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第" << (i+1) << "次访问:虚拟页 " << page << endl; manager.access_page(page); // 随机标记部分页面为脏页(模拟写操作) if (rand() % 3 == 0) { manager.modify_page(page); } } // 打印最终页表状态 manager.print_page_table(); return 0; }
代码说明(C++98 兼容要点)
  1. 禁用 C++11 特性:如nullptr(改用-1)、强类型枚举(改用普通枚举)、范围 for 循环(改用普通 for);
  2. 核心逻辑:模拟了 “缺页中断”、“空闲帧分配”、“简单页面置换” 三大核心流程;
  3. 可直接运行:无需依赖第三方库,g++ 编译时指定-std=c++98即可。
编译运行命令(Linux/macOS)
# 编译(指定C++98标准) g++ -std=c++98 demand_paging.cpp -o demand_paging # 运行 ./demand_paging

5.3 页面置换算法

页面置换算法是请求分页的核心,决定了 “内存满时淘汰哪个页面”,直接影响系统性能。

常见置换算法对比
算法名称核心思想优点缺点
最佳置换(OPT)淘汰 “未来最久不使用” 的页面缺页率最低无法实现(需要预知未来访问)
先进先出(FIFO)淘汰 “最先进入内存” 的页面简单易实现可能出现 “Belady 异常”(内存越多缺页率越高)
最近最少使用(LRU)淘汰 “最近最久未使用” 的页面接近 OPT,实用性强需要记录页面访问时间 / 次数
时钟算法(Clock)基于 “使用位” 循环淘汰,近似 LRU性能好,开销低略逊于 LRU
LRU 置换算法完整 C++98 实现(替换 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: vector<PageTableEntry> page_table; int total_physical_frames; vector<bool> 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第" << (i+1) << "次访问:虚拟页 " << 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 等高效置换算法
工作集模拟(C++98 代码)
#include <iostream> #include <vector> #include <set> #include <cstdlib> #include <ctime> using namespace std; // 工作集管理器 class WorkingSetManager { private: vector<int> access_history; // 页面访问历史 int window_size; // 工作集窗口大小(最近N次访问) set<int> 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 (vector<int>::iterator it = access_history.begin(); it != access_history.end(); ++it) { working_set.insert(*it); } } // 打印当前工作集 void print_working_set() { cout << "当前工作集(窗口大小=" << window_size << "):"; for (set<int>::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第" << (i+1) << "次访问:虚拟页 " << 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 请求分段存储管理方式

请求分段是虚拟存储器的另一种实现方式,与分页的核心区别是:分段按 “逻辑功能” 划分(如代码段、数据段),页是固定大小的物理块

核心原理
  1. 段的大小不固定,按程序的逻辑结构划分;
  2. 运行时仅加载当前需要的段,缺段时触发 “缺段中断”;
  3. 段表记录段的基址、长度、状态(内存 / 外存)等信息。
请求分段完整 C++98 代码实现
#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: vector<SegmentTableEntry> segment_table; // 段表 int total_memory_size; // 物理内存总大小(字节) vector<bool> 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第" << (i+1) << "次访问:段 " << 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 请求分页 核心区别(思维导图)

习题

基础题
  1. 简述虚拟存储器的核心特征,为什么需要虚拟存储器?
  2. 缺页中断与普通中断有何区别?
  3. 什么是 Belady 异常?哪些置换算法会出现该异常?
  4. 抖动的产生原因是什么?如何避免抖动?
  5. 对比请求分页和请求分段的优缺点,分别适用于什么场景?
编程题
  1. 基于本文的 LRU 代码,实现 Clock(时钟)置换算法;
  2. 扩展请求分页代码,统计 “缺页率”(缺页次数 / 总访问次数);
  3. 模拟多个进程共享物理内存,实现进程间的内存隔离。

总结

  1. 虚拟存储器的核心是 “部分加载、按需调页 / 调段”,解决了物理内存不足的问题,核心依赖缺页 / 缺段中断页面置换算法
  2. 请求分页是主流实现方式,LRU 是最常用的置换算法(接近最优),需避免 “抖动”(工作集超出物理内存);
  3. 请求分段按逻辑功能划分,适合共享 / 保护,但存在外部碎片问题,分页无外部碎片但逻辑性弱。

最后

所有代码均基于 C++98 标准编写,可直接编译运行,大家可以动手修改参数(如物理帧数、访问序列、窗口大小),观察不同场景下的运行结果,加深对虚拟存储器的理解!如果有问题,欢迎评论区交流~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/2 0:36:02

IQuest-Coder-V1按需付费方案:低成本GPU部署实战

IQuest-Coder-V1按需付费方案&#xff1a;低成本GPU部署实战 1. 为什么你需要关注这个模型&#xff1f; 你是不是也遇到过这些情况&#xff1a; 想在本地跑一个真正能写代码、能调试、能理解项目结构的大模型&#xff0c;但发现70B参数的模型动辄要两张A100&#xff0c;显存…

作者头像 李华
网站建设 2026/3/31 13:50:11

全面讲解cp2102usb to uart bridge芯片内部电路设计

以下是对您提供的博文内容进行 深度润色与工程化重构后的技术文章 。全文已彻底去除AI生成痕迹,强化了真实工程师视角的实战语感、设计权衡逻辑与一线调试经验;结构上打破传统“模块堆砌”,以 问题驱动+原理穿插+实测佐证+避坑指南 为主线自然展开;语言更贴近资深硬件工…

作者头像 李华
网站建设 2026/3/31 8:06:46

3大自动化场景提升80%效率:XAutoDaily的零代码配置方案

3大自动化场景提升80%效率&#xff1a;XAutoDaily的零代码配置方案 【免费下载链接】XAutoDaily 一个基于QQ的全自动签到模块 项目地址: https://gitcode.com/GitHub_Trending/xa/XAutoDaily XAutoDaily是一款基于QQ的全自动签到模块&#xff0c;通过智能任务调度系统实…

作者头像 李华
网站建设 2026/3/26 21:14:59

AI也能逛拼多多?Open-AutoGLM实战演示

AI也能逛拼多多&#xff1f;Open-AutoGLM实战演示 1. 这不是科幻&#xff0c;是今天就能用的手机AI助理 你有没有想过&#xff0c;让AI替你刷拼多多&#xff1f;不是简单地调用API查价格&#xff0c;而是真正“看”到屏幕、“理解”界面、“点击”按钮、“输入”搜索词、“滑…

作者头像 李华
网站建设 2026/3/14 9:51:26

参考文献格式总出错?Zotero国标配置3招解决学术写作痛点

参考文献格式总出错&#xff1f;Zotero国标配置3招解决学术写作痛点 【免费下载链接】Chinese-STD-GB-T-7714-related-csl GB/T 7714相关的csl以及Zotero使用技巧及教程。 项目地址: https://gitcode.com/gh_mirrors/chi/Chinese-STD-GB-T-7714-related-csl 你是否曾在提…

作者头像 李华
网站建设 2026/4/1 23:40:00

GPEN处理速度慢?CUDA加速部署教程让推理快3倍

GPEN处理速度慢&#xff1f;CUDA加速部署教程让推理快3倍 你是不是也遇到过这样的情况&#xff1a;上传一张人像照片&#xff0c;点击“开始增强”&#xff0c;然后盯着进度条等上半分钟&#xff1f;明明是GPU服务器&#xff0c;GPEN却跑得比CPU还慢&#xff1f;别急&#xff…

作者头像 李华