x86平台内存映射文件的内存类型(WB与USWC)探究
一、内存映射文件是不是USWC类型?
答案很明确:默认情况下不是。
USWC(无缓存推测写合并)是专门为GPU这类外设I/O设计的内存类型——它没有系统RAM作为后盾,读写请求会直接转发到硬件,靠写合并来降低I/O开销。但内存映射文件的本质是把磁盘文件映射到进程虚拟地址空间,底层完全依赖系统物理RAM作为页缓存,所以默认的缓存策略是和常规内存一致的WB(回写缓存):写操作先存到RAM缓存,后台再同步到磁盘;读操作优先从RAM缓存取,减少磁盘访问。
当然,你可以手动修改内存映射文件的缓存属性(比如Windows里用SEC_NOCACHE,Linux里调整页表缓存模式),但这也只能改成UC(无缓存)或WT(写通)这类,和USWC的“无RAM后盾”核心特性完全不同,普通内存映射文件也用不上USWC——毕竟它的基础就是页缓存。
二、x86_64 Windows的底层实现
Windows的内存映射靠页缓存和**虚拟内存管理器(VMM)**完成,流程大概是这样:
- 调用
CreateFileMapping创建文件映射对象,内核会生成一个节对象(Section Object),记录文件句柄、映射大小、缓存规则等信息。 - 用
MapViewOfFile把这个节对象映射到进程虚拟地址空间,VMM会给进程分配一块虚拟地址范围,同时把虚拟页和页缓存里的物理页绑定(页表项默认标记为WB)。 - 读写操作:第一次访问映射地址时触发缺页中断,内核从磁盘把对应文件内容读到页缓存,更新页表;写操作先写到缓存页,要么后台线程定期同步到磁盘,要么你调用
FlushViewOfFile手动刷新。
如果要改缓存属性,CreateFileMapping里可以指定SEC_NOCACHE(对应UC)或SEC_WRITECOMBINE(对应WC,有RAM后盾的写合并),但这俩一般是给硬件外设映射用的,普通文件用了反而会拖慢性能。
三、x86_64 Linux的底层实现
Linux这边靠mmap系统调用和页缓存搞定,核心流程:
- 调用
mmap时,内核会给进程分配一块虚拟地址范围,用vm_area_struct结构体记录这个区域的属性——比如是私有还是共享映射、权限、关联的文件指针等。 - 首次访问映射地址触发缺页中断,内核通过文件的
read方法把磁盘内容读到页缓存,然后更新页表项(默认标记为WB,对应x86_64的_PAGE_CACHE_MODE_WB)。 - 写操作:默认是写时复制(Copy-on-Write)——如果是私有映射,进程修改页时内核会复制一份新页,标记为脏页,后台由
pdflush或kswapd线程同步到磁盘;如果是共享映射,修改直接写到页缓存,最终同步到磁盘。
要调整缓存策略的话,可以用madvise设置预读或回收规则,或者通过pgprot_modify修改页表的缓存模式(比如改成WT或UC),但同样,USWC不适用普通内存映射文件——USWC没有RAM backing,而内存映射文件的核心就是依托页缓存来减少磁盘I/O。
核心区别对比
- OpenGL/Vulkan映射的显存:USWC类型,无RAM后盾,读写直接走GPU,靠写合并优化I/O。
- 内存映射文件:默认WB类型,依赖系统页缓存,读写先经过RAM,具备常规内存的缓存优势。
内容的提问来源于stack exchange,提问作者janekb04

