3.3 windows,ReactOS系统中页面的换出----1
系列文章目录
文章目录
- 系列文章目录
- 3.3 页面的换出
- MiBalancerThread()
- MmTrimUserMemory()
- MmPageOutVirtualMemory()
3.3 页面的换出
在前一节中我们看到,如果有映射的页面已经被倒换到磁盘上即倒换文件中,那么对这个页面的访问就会引起一次缺页异常,而相应的异常处理程序就会从磁盘上把这个页面倒换进来。这自然就会产生一个问题:这个页面是在什么时候又是怎样跑到磁盘上去的呢?当然,页面(的内容)不会自己跑到磁盘上,而得有个行为主体将其倒出到磁盘上,这个行为主体就是内核线程MiBalancerThread() .
MiBalancerThread()
VOID STDCALL
MiBalancerThread(PVOID Unused)
{PVOID WaitObjects[2];....WaitObjects[0] = &MiBalancerEvent;//通过Event唤醒WaitObjects[1] = &MiBalancerTimer;//通过定时器唤醒while (1){Status = KeWaitForMultipleObjects(2,WaitObjects,WaitAny,Executive,KernelMode,FALSE,NULL,NULL);if (Status == STATUS_SUCCESS){//因为事件而被(某个线程)唤醒/* MiBalancerEvent */CHECKPOINT;while (MmStats.NrFreePages < MiMinimumAvailablePages + 5){//循环,知道有一个数量的空闲物理页面for (i = 0; i < MC_MAXIMUM; i++){if (MiMemoryConsumers[i].Trim != NULL){//调用内存消费者的修剪函数NrFreedPages = 0;Status = MiMemoryConsumers[i].Trim(MiMinimumPagesPerRun, 0, &NrFreedPages);if (!NT_SUCCESS(Status)){KEBUGCHECK(0);}}}}InterlockedExchange(&MiBalancerWork, 0);CHECKPOINT;}else if (Status == STATUS_SUCCESS + 1){/* MiBalancerTimer *///因超时而被唤醒ShouldRun = MmStats.NrFreePages < MiMinimumAvailablePages + 5 ? TRUE : FALSE;for (i = 0; i < MC_MAXIMUM; i++)//对于所有的内存消费者{if (MiMemoryConsumers[i].Trim != NULL){NrPagesUsed = MiMemoryConsumers[i].PagesUsed;if (NrPagesUsed > MiMemoryConsumers[i].PagesTarget || ShouldRun){//本消费者占用页面数已超过配额,或总库存已降到危险点if (NrPagesUsed > MiMemoryConsumers[i].PagesTarget){Target = max (NrPagesUsed - MiMemoryConsumers[i].PagesTarget,MiMinimumPagesPerRun);}else{Target = MiMinimumPagesPerRun;//每次至少修剪的数量}NrFreedPages = 0;//执行本消费者的修剪函数Status = MiMemoryConsumers[i].Trim(Target, 0, &NrFreedPages);if (!NT_SUCCESS(Status)){KEBUGCHECK(0);}}}}}else{//因其他原因被唤醒,不应发生DPRINT1("KeWaitForMultipleObjects failed, status = %x\n", Status);KEBUGCHECK(0);}}
}
这个线程平时都在睡眠,但是周期性地通过事件MiBalancerTimer 被定时器唤醒。此外,这个线程也可以通过事件 MiBalancerEvent 被唤醒,这发生在需要分配物理页面却发现库存不足的时候每当这个线程被唤醒的时候,它就借助若干个内存“消费者(Consumer)”的“修剪函数”对内存加以“修剪(Trim)”。所谓修剪,就是把一些判断为暂时不会被访问的页面(的内容)倒换出去,腾出所占据的物理页面另行分配,
如前所述,所谓内存“消费者”并不是指实际占用着物理页面的进程,而是指各种不同的用途例如用户空间的页面映射,内核中的可倒换物理页面池、不可倒换物理页面池,磁盘上扇区内容的高速缓存等。内核中有个结构数组MiMemoryConsumers[],其中的每个元素都代表一个“消费者”其下标可以是:
#define MC_CACHE (0)
#define MC_USER (1)
#define MC_PPOOL (2)
#define MC_NPPOOL (3)
#define MC_MAXIMUM (4)
显然,每一种用途即“消费者”都应该提供自己的修剪函数:但是目前ReactOS只为MC_CACHE和MC_USER提供了修剪函数。换言之,另两种用途的页面是不让修剪的。其中用户空间页面所映射物理页面的修剪函数为MmTrimUserMemory()。
MmTrimUserMemory()
[MiBalancerThread()>MmTrimUserMemory()]/* FUNCTIONS *****************************************************************/NTSTATUS
MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
{PFN_TYPE CurrentPage;PFN_TYPE NextPage;NTSTATUS Status;(*NrFreedPages) = 0;CurrentPage = MmGetLRUFirstUserPage();//运用LRU算法找到第一个可以倒出的页面while (CurrentPage != 0 && Target > 0){NextPage = MmGetLRUNextUserPage(CurrentPage);//下一个可以倒出的页面//倒出物理页面 CurrentPageStatus = MmPageOutPhysicalAddress(CurrentPage);if (NT_SUCCESS(Status)){DPRINT("Succeeded\n");Target--;(*NrFreedPages)++;}else if (Status == STATUS_PAGEFILE_QUOTA)//已超过倒换文件的容量配额{MmSetLRULastPage(CurrentPage);//下次再来}CurrentPage = NextPage;}return(STATUS_SUCCESS);
}
参数Target是要求修剪的页面数量,NrFreedPages用来返回实际修剪的数量,另一个参数Priority实际上没有被用到。
修剪的对象是“最近最少被用到”的页面,相应的算法为LRU。与MiMemoryConsumers[]平行,内核中还有个队列头数组 UsedPageListHeads[],也是以 MC_USER 等为下标,凡是被分配用于某个消费者的物理页面,其数据结构都按LRU的次序挂在其队列中。LRU是一种常用的算法,我们就不深入到这里面去了。
找到修剪对象的物理页面号之后,就通过MmPageOutPhysicalAddressO)将其倒换出去。
MmPageOutVirtualMemory()
[MiBalancerThread()> MmTrimUserMemory() > MmPageOutPhysicalAddress()>MmPageOutVirtualMemory()]NTSTATUS
NTAPI
MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,PMEMORY_AREA MemoryArea,PVOID Address,PMM_PAGEOP PageOp)
{PFN_TYPE Page;BOOLEAN WasDirty;SWAPENTRY SwapEntry;NTSTATUS Status;DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",Address, AddressSpace->Process->UniqueProcessId);/** Check for paging out from a deleted virtual memory area.*/if (MemoryArea->DeleteInProgress){PageOp->Status = STATUS_UNSUCCESSFUL;KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);MmReleasePageOp(PageOp);return(STATUS_UNSUCCESSFUL);}/** Disable the virtual mapping.//关断目标页面的映射*/MmDisableVirtualMapping(AddressSpace->Process, Address,&WasDirty, &Page);if (Page == 0){KEBUGCHECK(0);}/** Paging out non-dirty data is easy.*/if (!WasDirty){//页面是干净的,物理页面空白或其内容与倒换文件中的对应页面完全相同MmLockAddressSpace(AddressSpace);MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);MmDeleteAllRmaps(Page, NULL, NULL);if ((SwapEntry = MmGetSavedSwapEntryPage(Page)) != 0){MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);MmSetSavedSwapEntryPage(Page, 0);}MmUnlockAddressSpace(AddressSpace);MmReleasePageMemoryConsumer(MC_USER, Page);PageOp->Status = STATUS_SUCCESS;KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);MmReleasePageOp(PageOp);return(STATUS_SUCCESS);}/** If necessary, allocate an entry in the paging file for this page*/SwapEntry = MmGetSavedSwapEntryPage(Page);if (SwapEntry == 0){SwapEntry = MmAllocSwapPage();if (SwapEntry == 0){MmShowOutOfSpaceMessagePagingFile();MmEnableVirtualMapping(AddressSpace->Process, Address);PageOp->Status = STATUS_UNSUCCESSFUL;KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);MmReleasePageOp(PageOp);return(STATUS_PAGEFILE_QUOTA);}}/** Write the page to the pagefile*/Status = MmWriteToSwapPage(SwapEntry, Page);if (!NT_SUCCESS(Status)){DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",Status);MmEnableVirtualMapping(AddressSpace->Process, Address);PageOp->Status = STATUS_UNSUCCESSFUL;KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);MmReleasePageOp(PageOp);return(STATUS_UNSUCCESSFUL);}/** Otherwise we have succeeded, free the page*/DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page << PAGE_SHIFT);MmLockAddressSpace(AddressSpace);MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);MmUnlockAddressSpace(AddressSpace);MmDeleteAllRmaps(Page, NULL, NULL);MmSetSavedSwapEntryPage(Page, 0);MmReleasePageMemoryConsumer(MC_USER, Page);PageOp->Status = STATUS_SUCCESS;KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);MmReleasePageOp(PageOp);return(STATUS_SUCCESS);
}
需要倒换出去的页面可能是“干净”的,也可能是“脏”的。
所谓干净的页面,是指自从上一次建立通向这个物理页面的映射以来从未对其进行过写操作的面,具体有两种可能:
1,这是个刚被分配并建立映射但从未被写过的空白页面。这样的页面在倒换文件中尚无对应的倒换页面,也不需要有,因为以后需要时可以重新分配一个空白页面。所以只要删除其映射,并通过 MmDeleteAlRmaps()使其与所属的进程脱钩,最后释放这个物理页面就可以了
2,这是个从倒换文件换入的页面,但是换入之后从未被写过。这样的页面在倒换文件中已经有了对应的倒换页面,但是不需要改变倒换页面的内容。对于这样的页面,一方面要删除其映射,另一方面要使相应的页面映射表项指向倒换文件中的页面。凡是有了倒换页面的物理页面,其PHYSICAL PAGE结构中的SavedSwapEntry字段就指向这个倒换页面,现在一方面将该字段的内容转移到相应的页面映射表项中(并将其PAPRESENT标志位清0),另一方面通过 MmSetSavedSwapEntryPage()将这个字段清 0。然后再释放这个物理页面。
倒换页面是由“倒换页面项”SWAPENTRY描述的,这是个32位无符号整数,实际上是倒换文件号与文件内页面号的组合
所谓脏的页面,则是指自从上一次建立通向这个物理页面的映射以来已经对其进行过写操作的面,具体又有两种可能:
1,这本是个刚被分配并建立映射的空白页面,但是现在已经不再空白。这样的页面在倒换文件中尚无对应的倒换页面,但是需要有。所以通过MmAllocSwapPageO)分配一个倒换页面这个函数返回一个SWAPENTRY,说明是哪一个倒换文件中的哪一个页面。然后通过MmWriteToSwapPage()将页面的内容写入倒换文件,再将相应的页面映射表项改成指向倒换页面(并将其 PA_PRESENT标志位清0),最后释放该物理页面。
2,这是个从倒换文件换入的页面,但是换入之后已经被写过。这样的页面在倒换文件中已经有了对应的倒换页面,但需要改变其内容。所以也由MmWriteToSwapPageO)将页面的内容写入倒换文件,再将相应的页面映射表项改成指向倒换页面(并将其PA_PRESENT标志位清 0),最后释放该物理页面。
至于 MmWriteToSwapPage(),则已经属于文件操作的范畴,这里就不深入下去了。最后再概括一下倒换页面与物理内存页
面和页面映射表项PTE之间的关系:
1,如果(虚存)页面的内容在物理页面中,则相应的PTE指向该物理内存页面,而物理内存页面的 PHYSICAL_PAGE结构中的SavedSwapEntry 字段指向作为后备的倒换页面。
2,如果(虚存)页面的内容不在物理页面中,则相应的PTE直接指向倒换页面。
相关文章:

3.3 windows,ReactOS系统中页面的换出----1
系列文章目录 文章目录 系列文章目录3.3 页面的换出MiBalancerThread()MmTrimUserMemory()MmPageOutVirtualMemory() 3.3 页面的换出 在前一节中我们看到,如果有映射的页面已经被倒换到磁盘上即倒换文件中,…...

QCustomPlot添加自定义的图例,实现隐藏、删除功能(二)
文章目录 实现步骤:详细代码示例:实现原理和解释:使用方法:其他参考要实现一个支持复选框来控制曲线显示和隐藏的自定义 QCPLegend 类,可以通过继承 QCPLegend 并重写绘制和事件处理方法来实现,同时发出信号通知曲线的状态变更。 实现步骤: 继承 QCPLegend 类,添加绘…...

Linux云计算 |【第五阶段】CLOUD-DAY8
主要内容: 掌握DaemonSet控制器、污点策略(NoSchedule、Noexecute)、Job / CronJob资源对象、掌握Service服务、服务名解析CluterIP(服务名自动发现)、(Nodeport、Headless)、Ingress控制器 一…...

岛屿数量 广搜版BFS C#
和之前的卡码网深搜版是一道题 力扣第200题 99. 岛屿数量 题目描述 给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。…...

hive切换表底层文件类型以及分隔符
1、改底层文件存储类型,但是一般只会在数据文件与期望类型一致的时候使用,比如load等方式时发现建表时没指定对这样的,因为这个语句不会更改具体的底层文件内容,只改元数据 ALTER TABLE 表名 SET FILEFORMAT 希望类型;2、更改数据…...

ChatGPT o1与GPT-4o、Claude 3.5 Sonnet和Gemini 1.5 Pro的比较
全新的ChatGPT o1模型(代号“Strawberry”)是OpenAI的最新进展,专注于以前的AI模型难以应对的领域:高层次推理、数学和复杂编程。OpenAI设计o1模型以花费更多时间思考问题,使其在需要逐层推理的任务中提高准确性。本文…...

asp.net文件防盗链
URLRewriter实现 可以参考下面的文章 代码 .net framework 新建asp.net framework的web项目,新建AntiTheftChainHandler using System.Web;namespace AntiTheftChainStu01.Handler {public class AntiTheftChainHandler : IHttpHandler{public bool IsReusable…...

【日志】力扣58.最后一个单词的长度//14.最长公共前缀//28. 找出字符串中第一个匹配项的下标
2024.11.6 【力扣刷题】 58. 最后一个单词的长度 - 力扣(LeetCode)https://leetcode.cn/problems/length-of-last-word/?envTypestudy-plan-v2&envIdtop-interview-150 int lengthOfLastWord(char* s) {int count 0;for (int i strlen(s) - 1; i…...

华为杯”第十五届中国研究生数学建模竞赛-B题:光传送网建模与价值评估(续)
目录 4. 问题二 光传送网规划 4.1 基本假设 4.2 模型建立 4.3 子问题一 4.2 子问题二 4.5 子问题三 5. 问题三 改善星座图 5.1 问题简述 5.2 问题分析 5.3 建模与问题求解 5.3.1 方案一 5.3.2 方案二 6. 模型评价 6.1 模型的优点 6.2 模型的缺点 参考文献 本文篇幅较长,分为上…...

android 使用xml设置背景图片和圆角
使用xml设置背景图片和圆角 <?xml version"1.0" encoding"utf-8"?> <layer-list xmlns:android"http://schemas.android.com/apk/res/android"><item><shape><solid android:color"android:color/transparen…...

数据结构,问题 E: 表达式括号匹配
题目描述 假设一个表达式有英文字母(小写)和数字、运算符(,—,*,/)和左右小(圆)括号构成,以“”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号…...

国家宠物美容师职业技能等级评价(高级)理论考试题
国家宠物美容师职业技能等级评价 理论考试复习参考范围 高级/三级 宠物美容师(高级)理论考试题 一 判断题 犬只的世界只有黑白灰三种,通过颜色呈现的深浅度进行辨识(A ) A 对 B 错 美国养犬俱乐部简称AKC…...

Spring挖掘:(AOP篇)
学习AOP时,我们首先来了解一下何为AOP 一. 概念 AOP(面向切面编程,Aspect Oriented Programming)是一种编程技术,旨在通过预编译方式或运行期动态代理实现程序功能的统一管理和增强。AOP的主要目标是在不改变原有业务逻辑代码的…...

十四届蓝桥杯STEMA考试Python真题试卷第二套第四题
来源:十四届蓝桥杯STEMA考试Python真题试卷第二套编程第四题:糖果罐调整 该题解通过贪心策略在每一步都选择对当前状态最有利的操作,从而达到最少调整次数的目标。 题目描述 现有 N 罐糖果,且已知每罐糖果的初始数量。现给出两个数值 L 和 R(L≤R),需要把每罐糖果的数…...

单元测试怎么做
单元测试是软件开发中非常重要的一部分,能够确保代码的正确性、可靠性和可维护性。对于 Vue 项目来说,单元测试主要关注的是测试组件及其相关功能是否正常。下面是如何在 Vue 项目中进行单元测试的详细步骤,包括测试框架的选择、测试工具的配…...

移动应用开发 实验二:标准身高计算器
文章目录 准备工作一,创建Android Studio项目二,创建活动模块三,设计用户界面(一)设置页面布局(二)添加标题文本控件(三)设计体重输入框(四)设计性…...

金华迪加现场大屏互动系统 mobile.do.php 任意文件上传漏洞复现
0x01 产品描述: 金华迪加现场大屏互动系统是由金华迪加网络科技有限公司开发的一款专注于增强活动现场互动性的系统。该系统设计用于提供高质量的现场互动体验,支持各种大型活动,如企业年会、产品发布会、展览展示等。其主要功能包…...

使用 pd.ExcelWriter 创建多工作表 Excel 文件的详细教程
with pd.ExcelWriter(...) as writer 可以将多个内容写入一个 Excel 文件中。具体地说,它创建了一个Excel 文件写入器,使得我们可以在一个文件中创建多个工作表(Sheet)。 with pd.ExcelWriter("模型指标和损失值.xlsx")…...

驱动-----dht11温湿度传感器
单总线:只用一根线。 复位信号:设置为输出模式,低电平20ms,然后再拉高30us。然后设置为输入模式,dht11会先拉低80us,然后拉高80us表示对接成功 数据0:开始先拉低50us,然后拉高26~28u…...

Docker 基础命令简介
目录 Docker 基础命令 1. Docker 版本信息 2. 获取 Docker 帮助 3. 列出所有运行中的容器 4. 运行一个新的容器 5. 查看容器日志 6. 停止容器 7. 启动已停止的容器 8. 删除容器 9. 列出所有镜像 10. 拉取镜像 11. 构建镜像 12. 删除镜像 13. 执行命令 14. 查看容…...

嵌入式开发之静态库和共享库
静态库 静态库的特点: 默认执行库链接的时候,检索的是Linux的/lib、/usr/lib目录下,如果指定gcc -c .... -L 指定路径 -l指定库文件;c语言分为预编译、编译、汇编、链接四个步骤。链接的时候是把依赖库文件函数的代码拷贝到程序里面,即便是删除库文件。拷贝后的程序依旧…...

关于npm源的切换及相关操作
要查看当前配置的 npm 源(registry),可以使用以下命令: 查看 npm 源 npm config get registry这个命令会返回目前被设置的 npm registry URL,通常情况下是 https://registry.npmjs.org/。 列出所有 npm 配置项 如果…...

vue前端sku实现
this.value.skuStockList [];let skuList this.value.skuStockList;//只有一个属性时if (this.selectProductAttr.length 1) {let attr this.selectProductAttr[0];for (let i 0; i < attr.values.length; i) {skuList.push({spData: JSON.stringify([{key:attr.name,v…...

使用Vue3和Vue2进行开发的区别
使用Vue3和Vue2进行开发的区别 笔者虽然老早就是用vue3进行开发了,但是上次有人问道使用vue3进行开发跟使用vue2进行开发的区别有哪些这个问题的时候,回答的还是有些琐碎,干脆今天专门整理一下,做个记录。 一、再也不用set了 众所…...

爬虫入门urllib 和 request(二)
文章目录 1、urllib介绍2、urllib的基本方法介绍2.1 urllib.Request2.2 response.read() 3、urllib请求百度首页的完整例子4、小结 1、urllib介绍 除了requests模块可以发送请求之外, urllib模块也可以实现请求的发送,只是操作方法略有不同! urllib在python中分为urllib和url…...

【大数据学习 | HBASE】hbase的整体架构
hbase的region存储原理图 首先我们看到hbase的组成分为两个大的部分,分别是hmaster和hregionserver,主节点用于协调数据,regionserver用于真正的去管理表,其中regionserver存在多个,他们共同协调管理全有的表ÿ…...

群控系统服务端开发模式-应用开发-个人资料
群控系统服务端开发模式后端基础框架现在就差个人资料、及权限验证。下面开发个人资料。 一、获取个人信息 1、添加路由 在根目录下route文件夹下面app.php文件中添加如下代码: Route::post(member/personal_data,permission.Member/personalData);// 获取个人信息…...

openssl生成加密,公钥实现非对称加密
私钥用于加密,公钥用于解密 私钥用于颁发token,公钥用于验证token,公钥不能颁发token 私钥和公钥是一对,不能单独使用,利用私钥生成公钥,利用公钥进行解密 使用openssl来生成一对私钥和公钥:ope…...

[CKS] K8S Admission Set Up
最近准备花一周的时间准备CKS考试,在准备考试中发现有一个题目关于Admission。 Whats Admission Kubernetes Admission是Kubernetes集群中一种机制,用于控制和修改集群中的资源对象。它允许您在Kubernetes资源被创建、更新或删除之前,对资源…...

前端学习Day13 CSS盒子的定位(固定定位篇“附练习”)
一、固定定位 固定定位 (position:fixed)其实是绝对定位的子类别,一个设置了 position:fixed 的元素是相对于视窗固定的,就算页面文档发生了滚动,它也会一直待在相同的地方。 ⚠️:固定定位会脱离文档流。…...