缺页产生原因
malloc
()
和
mmap
()
等内存分配函数,在分配时只是建立了进程虚拟地址空间,并没有分配虚拟内存对应的物理内存。当进程访问这些没有建立映射关系的虚拟内存时,系统触发缺页中断,缺页中断机制根据所访问页面的状态来分配物理页面并建立映射关系。
触发
缺页中断的情况有两种
,
第一,程序访问了非法地址
;第二
,访问的地址是合法的,但是该地址还未分配物理页框。本文基于linux 5.10.13,学习书籍 :奔跑吧linux
请搭配代码进行阅读更佳~
产生缺页中断的情况
匿名页面、
概念:系统零页
zero page是一个特殊的物理页,里面值全部为0,zero page是针对匿名
页场景专门进行优化,主要是节省内存和对性能进行了一定优化。当malloc或者
map
一段虚拟内存后,第一次对该内存访问为读操作,将会发生匿名page fault。do_anonymous_page处理,由于第一次为读操作还未发生写操作,因此发生一个zero page,为其申请一个特殊物理页zero page。 ARM64
中
empty_zero_page
全局数组
流程
匿名
页缺页异常
,匿名映射
完成之后
,获得
了一块虚拟内存,并没有分配物理内存,当第一次访问的时候:
如果是读访问,会将虚拟页映射到0页,以减少不必要的内存分配
如果是写访问,用
alloc_zeroed_user_highpage_movable
分配新的物理页,并用0填充,然后映射到虚拟页上去
如果是先读后写访问,则会发生两次缺页异常
:
第一次
是匿名页缺页异常的读的处理(虚拟页到
0
页的映射),第二次是写时复制缺页异常处理。借一张网图说明流程
![](https://img-blog.csdnimg.cn/4ca6a148121f458099df050e4e62be39.png)
文件映射
![](https://img-blog.csdnimg.cn/efe95cbae5104834bdc09271cc2e80b9.png)
代码中的流程
映射fault地址附近几页可以提高速度,下一次访问就有概率不会再发生缺页中断,具体的fault处理基于文件系统实现,图中以ext4文件系统为例,
do_fault_around
do_cow_fault
do_share_fauly
其中涉及到脏页,RMAP等概念就不一一展开
do_fault
写时复制
概念:
•
创建子进程时,将父进程的 虚拟内存 与 物理内存 映射关系复制到子进程中,并将内存设置为只读(设置为只读是为了当对内存进行写操作时触发 缺页异常)。
•
•
当子进程或者父进程试图对只读内存数据进行修改时,便会触发写时复制机制:将原来的内存页复制一份新的,并重新设置其内存映射关系,将父子进程的内存读写权限设置为可读写。
老规矩 借一张网上以及总结得很好的图
![](https://img-blog.csdnimg.cn/9af0eccab02f4f02a5bf32b530fc24a5.png)
do_wp_fault流程
其中的主要函数,配合代码食用哟
wp_page_copy:处理写时复制
wp_page_resue:处理可复用的物理页面
wp_page_shared:处理可写,共享的普通映射页面,是使用wp_page_reuse完成缺页异常处理
wp_pfn_shared:处理可写,共享的普通映射页面,是使用wp_page_reuse完成缺页异常处理
wp_page_copy
获取缺页异常页面,更新
PTE
的可写标志位,设置新的
PTE
,加入
LRU
链表,更新
TLB,page
cache
![](https://img-blog.csdnimg.cn/176b27b457f547678c735a82eab1aab6.png)
•wp_page_reuse
用于复用缺页异常的物理页面
-----------------一些代码中的总结
page1
的映射计数
_
mapcount
为
2代表被两个进程映射,类似于父子进程未写时复制时,
分配好page后count--