首页/新闻资讯/正文详情

Linux 内存管理:mmap 了 1 页内存,读它为什么一分钱不花?

发布时间:2026/11/4 23:08:18 来源:云帆数科 栏目:资讯中心
Linux 内存管理:mmap 了 1 页内存,读它为什么一分钱不花?
mmap 了 1 页内存读它为什么一分钱不花写 C 的人大概都用过 mmap向内核申请一段内存拿到地址就能读写。直觉上申请了就是占了读一下总该分到物理内存吧下面这段程序只申请了 1 页先读一次再写一次#includesys/mman.h#includestdio.h#definePAGE_SIZE4096intmain(){size_tmap_sizePAGE_SIZE;void*addrmmap(NULL,map_size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);volatilecharc*(char*)addr;/* 读触发缺页 */*(char*)addrA;/* 写再次触发缺页 */printf(%c\n,c);return0;}先把直觉摆到台面上申请了就是占了读了就该分 1 页RSS 涨 4KB。实测结果却不是这样读不花写才花。更怪的是“读完再写”和“上来就写”走的根本不是同一条内核路径。申请了 1 页读一下真的免费吗要回答这个问题不能只看代码猜得让内核自己说。我用 eBPF 给内核挂了几个探针专门盯着缺页处理里几个关键函数看它们到底有没有被触发。实验很简单三个小程序其他条件全一样每组只 mmap 1 页只改碰内存的方式只读、直接写、读后写。实验在 QEMU Linux 6.17 里做Ubuntu 25.10x86_64 KVM内核开了 BTF方便eBPF调试。结果整理成一张对照表碰法本以为会怎样内核实际做了什么结果只读分配函数会来读了就分 1 页只有 do_anonymous_pageflags0x1a54不带写标志分配事件、do_wp_page 都没出现读没分新页直接写分配函数会来写了就分 1 页do_anonymous_pageflags0x1a55带写标志 分配事件 vma_alloc_folio_noproforder0首触写真的分配一页读后写第二次写还会进 do_anonymous_page第二次写不再进 do_anonymous_page而是进了 do_wp_pageflags0x1a55后跟分配事件 vma_alloc_folio_noproforder0据此排除 wp_page_reuse、判定为 wp_page_copy读过的页一写还要拷一遍读和写的 flags 只差最后一位0x1a54 是读0x1a55 是写正好就是写标志这一位。这里要交代一个细节wp_page_copy 和 wp_page_reuse 在内核里都是 inline 函数探针挂不到它们本体。所以读后写那一行不是“探针抓到了 wp_page_copy”而是“探针抓到了 do_wp_page 分配事件”。copy 一定要分配新页reuse 不用分配有分配事件就能排除 reuse这才是判定为 copy 的依据。分配事件在 trace 里叫 vma_alloc_folio_noprof它是 wp_page_copy 经 folio_prealloc、vma_alloc_zeroed_movable_folio、vma_alloc_folio 走下来的下游。读后写这条路的调用关系画出来是这样handle_pte_fault └── do_wp_page ├── wp_page_reuse # 不分配只标可写 └── wp_page_copy # 必分配 └── folio_prealloc - vma_alloc_zeroed_movable_folio - vma_alloc_folio - vma_alloc_folio_noprof到这里第二个怪现象已经藏不住了**写就是写怎么还分两条路**答案在缺页处理里。三种碰法三条路先说一个前提mmap 返回后内核只是在进程的地址空间链表里记下了这段虚拟地址没有分配任何物理页也没有建立任何页表项。虚拟内存的“申请”和物理内存的“占用”是两回事缺页中断才是真正花钱的时刻。CPU 访问还没建页表的地址就会触发缺页经 do_user_addr_fault 进入 do_anonymous_page之后按碰法分流读先借一张零页。这不是写缺页没有写标志进程也没有禁用零页!mm_forbids_zeropage于是走零页分支entrypte_mkspecial(pfn_pte(my_zero_pfn(addr),vma-vm_page_prot));内核把虚拟地址映射到全局唯一的一张 Zero Page并把页表项标为 special。读到的全是 0需求满足了物理内存一分没花。直接写分一张新页。写缺页同样进 do_anonymous_page但走分配分支调用vma_alloc_zeroed_movable_folio申请新页实测 trace 里表现为下游的vma_alloc_folio_noprof再用set_ptes建立可写映射。这时才完成虚拟内存到物理内存的实质性绑定。读后写把零页复印一张。这时页表项已经存在了只不过指向零页且不可写。所以写缺页不再进 do_anonymous_page而是进 do_wp_page也就是写保护缺页的通用处理。do_wp_page 发现这是一个 special 页表项vm_normal_page取不到正常页于是走wp_page_copyinline实测中以 do_wp_page 后的分配事件为据见上表分配一个真正的匿名页建立可写映射。零页本身永远不会被写写操作永远发生在新页上。一句话读走零页分支首触写走分配分支读后写走 do_wp_page 的拷贝分支。三条路三种代价。两本账虚拟的“有”物理的“占”延迟分配的核心就一句话虚拟地址的“有”和物理内存的“占”是两本账缺页中断是结账的时刻而结账的方式取决于你怎么碰它——读记一笔零页的账写才真正掏钱。这篇实验还让我重新确认了一件事证据必须和机制有因果探针抓到 do_anonymous_page 还是 do_wp_page本身就是走了哪条路的判定函数本体被 inline 时区分依据就是它下游必然产生或不产生的事件比如 do_wp_page 后的分配事件PFN 和 RSS 只是可选的旁证。写应用时记住这几点说到底读是借写才是拥有内核把账单往后推写应用的人就得在账单到期那一刻想清楚别用虚拟大小衡量内存占用。mmap 成功不等于内存到手真正花钱的是你碰过的页。大块 mmap 加稀疏访问只花碰过的页反过来只看虚拟大小做容量评估会高估很多。第一次写的代价别留在关键路径上。首触写要缺页、分配、建页表时延敏感的代码最好在启动或空闲时把热页先写一遍热身反过来不用的大内存也别提前全量 memset那等于亲手把延迟分配的好处毁掉。只读的页别顺手写。读到的零页是大家共用的一写就变成自己的私有页还要走拷贝分支。哪怕写回相同的值也会触发分配确定要全页重写时直接写比先读后写少走一层分支。需要保证时别只靠 mmap 返回。写时分配才可能失败失败可能落在业务中途。要求稳的场景在启动时就把关键内存触碰一遍、尽早处理失败或者用 mlock 锁定把风险尽量留在启动时。你第一次被 mmap“骗”是什么时候欢迎在评论区说说。

相关推荐

机器学习-支持向量机
机器学习-支持向量机

二维二分类,看决策边界和支持向量import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_moons from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC# 1. 生成… · 2026/11/4 23:08:18

AI 编程额度怎么用才不浪费?
AI 编程额度怎么用才不浪费?

下午三点多,一个线上 bug 改到一半,Claude Code 停住了:额度用完,几点恢复 回想上午:读了一遍没看过的模块,跑了两轮测试,顺手整理了几次提交说明。单看都不重,加起来,把… · 2026/11/4 23:08:18

C++ std::sort 的比较器 <= 和 < 只差一个字符,行为却天差地别
C++ std::sort 的比较器 <= 和 < 只差一个字符,行为却天差地别

C std::sort 的比较器 < 和 < 只差一个字符&#xff0c;行为却天差地别 flyfishC 排序代码能编译、能运行、大多数时候结果还是对的&#xff0c;但一旦数据里出现相等元素&#xff0c;它就会以各种诡异的方式出错。一、先说一个场景 假设在维护一段视频流处理的代码&… · 2026/11/4 23:07:17

8G显存本地AI数字人实战:从ASR到TTS的完整搭建与调优指南
8G显存本地AI数字人实战:从ASR到TTS的完整搭建与调优指南

8G显存在AI本地化圈子里处境挺尴尬的&#xff1a;你说它能跑模型吧&#xff0c;7B量化之后勉强能聊&#xff1b;你说它跑不好吧&#xff0c;又确实比集显强太多。大多数教程讲的都是怎么用Ollama跑一个聊天模型&#xff0c;但很少有人说可以更进一步——把它变成一只能听懂人话… · 2026/11/5 0:00:39

大模型系统性入门:从原理、部署到微调应用的完整路线
大模型系统性入门:从原理、部署到微调应用的完整路线

1. 为什么你收藏了300个教程&#xff0c;依然觉得大模型没入门我先讲一个前几天在交流群里看到的真实场景&#xff1a;有人问"大模型怎么入门"&#xff0c;群里立马有人甩出几个网盘链接&#xff0c;里面躺着几百个PDF和视频&#xff0c;说是"全网最全的大模型学… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师&#xff0c;我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码&#xff0c;在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门&#xff0c;我先说个结论&#xff1a;这事真不难&#xff0c;难的是资料太散、路线太多&#xff0c;今天这个框架明天那个工具&#xff0c;新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时&#xff0c;Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

Mac软件下载站分类指南:四类渠道与安全判断标准
Mac软件下载站分类指南:四类渠道与安全判断标准

Mac用户找软件这件事&#xff0c;说大不大&#xff0c;说小也真不小。我用了十来年Mac&#xff0c;从最早在论坛里翻帖子找注册码&#xff0c;到后来自己维护一份资源清单&#xff0c;踩过的坑能写满一页纸&#xff1a;下到过套壳安装包、遇到过捆绑浏览器主页的“绿色版”、也… · 2026/11/4 23:59:37

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时&#xff0c;Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门&#xff0c;我先说个结论&#xff1a;这事真不难&#xff0c;难的是资料太散、路线太多&#xff0c;今天这个框架明天那个工具&#xff0c;新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师&#xff0c;我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码&#xff0c;在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码