案例
“兵马未到、案例先行”,先看看二者的区别吧!
🌰一句话案例:浏览器标签页的显存管理
- 常规分页:浏览器加载新图片时,系统分页进程将图片数据从内存 → 显存(传输),初始化显存(填充)。
- 例外分页:切换标签页时,渲染线程暂停,更新页表(新图片的虚拟地址 → 显存映射),刷新 TLB(确保 GPU 用新地址)。
- 结果:新标签页的图片正确显示,无地址冲突(避免旧标签页的地址干扰)。
如图 1 所示,浏览器进程 通过 GPU 虚拟地址 映射到 ->GPU 物理显存中,完成数据读取
图 1 浏览器显示图片简单示意图
如图 2 所示,当浏览器需要显示新的图片,该图片位于内存中,则会触发** [ 内存->显存 ] 的分页操作**
- copy 操作: picture2 数据会覆盖 picture1;
图 2 浏览器显示图片简单示意图
如图 3 所示,当需要读取 VARM 的另外一部分数据的时候,则会涉及** [ 页表更新 ] 的分页操作**
- copy 操作(可选):如果需要的数据还在 DRAM 中,则需要先将它拷贝到 VRAM 的某块显存中。
- update page table:需要将 GPUVA 虚拟地址 重新映射到 VRAM 中的 picture2 上。
一、分页的本质:虚拟内存的「翻译官」
分页(Paging)是操作系统管理内存的核心机制,解决「程序虚拟地址 → 物理内存(含显存)」的映射问题。
核心目标:让程序以为自己拥有连续的大内存(虚拟地址空间),实际由系统动态分配物理内存(内存 / 显存),通过页表(地址翻译蓝图)实现映射。
二、分页包含的 5 大核心操作(含页表更新!)
根据微软文档和图形驱动原理,分页操作分为以下类别(附工厂流水线类比):
操作类型 | 技术定义 | 工厂类比 | 是否属于分页操作? |
---|---|---|---|
1. 内存数据传输 | 系统内存 ↔ 显存的分配转移(如纹理加载到显存) | 管理员搬运零件(仓库 ↔ 流水线) | ✅ 核心操作 |
2. 填充模式(Pattern Fill) | 初始化显存分配(如清空内存为 0,或填充测试图案) | 工人给零件涂底色 | ✅ 辅助操作 |
3. 页表更新(Page Table Update) | 修改虚拟地址 → 物理显存的映射关系(重点!) | 修改流水线蓝图(零件位置) | ✅ 核心操作(特殊场景) |
4. 映射到孔径段(Aperture Map) | 将显存暴露给 CPU 访问(通过 PCIe 总线的固定地址空间) | 开放车间特定区域给仓库管理员 | ✅ 地址管理操作 |
5. 刷新 TLB(Translation Look-aside Buffer) | 清除 GPU 的地址缓存,强制使用新页表(避免缓存旧映射) | 通知工人忘记旧蓝图(用新地图) | ✅ 配套操作 |
三、页表更新的「双重身份」:既是分页操作,又是「例外操作」
- 属于分页操作的原因:
页表是分页机制的核心数据结构,更新页表是「修改虚拟地址映射」的直接行为,符合分页的定义(如进程切换时的页表更新)。 - 例外之处:执行上下文不同:
- 常规分页操作(如数据传输):由系统分页进程异步执行(后台办公室处理,不阻塞流水线)。
- 页表更新(
UpdateGpuVirtualAddress
):由渲染线程的伴随上下文同步执行(必须暂停流水线,当面改蓝图)。
- 类比:
- 常规分页:仓库管理员悄悄搬运零件(不影响流水线)。
- 页表更新:工程师必须进入车间,等流水线暂停后修改每台机器的蓝图(同步操作)。
四、分页操作的完整流程案例:游戏加载新场景
- 步骤 1:数据传输(分页进程)
- 场景资源(纹理、模型)从硬盘 → 系统内存 → 显存(
Transfer allocation
)。 - 类比:零件从仓库 → 暂存区 → 流水线工位。
- 场景资源(纹理、模型)从硬盘 → 系统内存 → 显存(
- 步骤 2:填充模式(分页进程)
- 初始化显存分配(如清除旧数据,填充默认值)。
- 类比:工人清洁工位,准备新零件。
- 步骤 3:页表更新(同步伴随上下文)
- 渲染线程暂停流水线,更新虚拟地址 → 新显存的映射(
UpdateGpuVirtualAddress
)。 - 类比:暂停流水线,工程师修改每台机器的蓝图(新零件位置)。
- 渲染线程暂停流水线,更新虚拟地址 → 新显存的映射(
- 步骤 4:映射孔径段(分页进程)
- CPU 通过固定地址访问显存(如读取渲染结果)。
- 类比:开放流水线出口,让仓库管理员取货。
- 步骤 5:刷新 TLB(伴随上下文)
- GPU 丢弃旧地址缓存,强制使用新页表。
- 类比:通知所有工人:“旧蓝图作废,现在用新地图!”
五、为什么页表更新必须被纳入分页操作?
- 分页的核心使命:维护虚拟地址映射的正确性。
- 没有页表,虚拟内存就失去意义(无法翻译地址)。
- 显存的特殊性:
- GPU 流水线并行度高,地址映射错误会直接导致渲染失败(花屏、崩溃)。
- 页表更新必须与渲染同步(常规分页的异步操作无法满足实时性)。
六、总结
分页操作的「常规」VS「例外」
分类 | 操作内容 | 执行者 | 同步性 | 关键作用 |
---|---|---|---|---|
常规分页 | 数据传输、填充、孔径映射、TLB 刷新 | 系统分页进程(异步) | 无需同步 | 内存搬运与基础管理 |
例外分页 | 页表更新(核心!) | 渲染伴随上下文(同步) | 严格同步渲染 | 确保地址映射与渲染原子性 |
最终答案:分页包含哪些操作?更新页表算不算?
- 分页操作全集:
🔹 数据传输(系统内存 ↔ 显存)
🔹 显存初始化(填充模式)
🔹 页表更新(虚拟地址 → 显存映射修改)
🔹 孔径段映射(CPU 访问显存)
🔹 TLB 刷新(清除地址缓存) - 更新页表的地位:
✅ 属于分页操作,且是核心操作(没有页表,虚拟地址无法翻译)。
⚠️ 特殊之处:通过同步伴随上下文执行(其他分页操作异步),确保与渲染严格同步。
开发者注意:分页操作的性能优化
- 减少同步页表更新:批量处理显存分配(如一次加载多个纹理的页表),避免频繁触发
UpdateGpuVirtualAddress
。 - 利用异步操作:数据传输、填充等常规分页操作可在后台并行执行(不阻塞渲染)。
- 监控 TLB 刷新频率:过高的刷新会导致 GPU 流水线停顿(类似工厂频繁改蓝图,工人反复停工),需平衡地址更新与性能。
理解分页操作的本质(尤其是页表更新的特殊性),能让开发者更精准地优化内存管理,避免 “异步更新导致的渲染错误”,同时利用系统分页进程的高效性提升整体性能。这对图形密集型应用(游戏、CAD、VR)尤为关键 —— 每一次地址映射的正确性,都决定了最终画面的质量与稳定性。