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. 查看容…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...
FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...
