新书推荐:1.3 内存管理模式

本节必须掌握的知识点:

        4GB虚拟空间

        虚拟内存

        多任务切换

1.3.1 4GB虚拟空间

       ■Win16操作系统

Windows1.0版本为16位操作系统,支持16位处理器实模式,最大寻址空间为1MB。Win16操作系统的内存管理非常简单,采用分段内存管理模式,最小段为16个字节,最大段为64KB,整个1MB内存空间都是透明的,没有任何访问限制。逻辑地址为“段值:偏移”,段值和偏移都是16位。将段值左移4位+偏移得到物理地址。在这种模式下,CPU的寄存器的宽度为16位,因此C语言的int数据类型的宽度也是16位。

Win32操作系统

当体系结构从16位到32位的时候,Windows API及其语法发生了最大改变。Windows1.0到3.1版本一直采用16位的分段内存管理模式。为了保证兼容性,INTEL的386之后的32位处理器也都支持这一模式。从Windows NT及Windows 95开始,利用32位intel 386、486以及奔腾处理器,Windows开始支持32位的flat平坦内存管理模式。C语言的int数据类型也因此扩展成32位宽。

Windows32位应用程序按照32位最大寻址范围4GB虚拟空间编写源程序。由于Win32操作系统为保护模式,普通应用程序只具有R3权限,只可以访问低2GB虚拟内存空间(高2GB空间为操作系统内核),在源程序中只需要使用32位偏移地址。

在32位保护模式中,仍然采用分段和分页模式管理内存空间。32位段基址为起始地址,源程序中的32位偏移地址为段内偏移。想要将源程序中的32位偏移地址转换为物理地址需要经过两个步骤:

●步骤一:将32位源程序中的逻辑地址转换为32位线性地址。

转换方法为:32位段基址+32位偏移地址=32位线性地址。

新的问题来了,在32位处理器中的段寄存器只有16位,且段寄存器数量只有6个。由于段寄存器无法存放32位段基址。为此,Windows操作系统设计了段选择子和段描述符表,段选择子为16位,作为段描述符表的索引存入段寄存器。段描述符表的每个表项为一个64位值,其中32位为段基址,20位为段界限域(定义段大小),12位段属性(定义段权限)。描述符表项的索引为13位,作为段选择子的高13位。段选择子的第0位和第1位存放RPL(段权限请求R0~R3)。段选择子第2位为0时,表示访问全局段描述符表并查找段基址,第2位为1时,表示访问局部段描述符表并查找段基址。找到对应的段基址后,再加上32位偏移地址就得到了32位线性地址。

那么如何找到段描述符表呢?为此,32位处理器增加了GDTR全局段描述符表寄存器、LDTR局部段描述表寄存器、中断描述符表寄存器IDTR和任务TR寄存器。GDTR寄存器为48位寄存器,存储全局段描述符表的32位地址和16位段界限。指令LGDT和SGDT分别用于加载和保存GDTR寄存器的内容。操作系统中只有一个GDT全局段描述符表。局部描述符表寄存器LDTR和任务寄存器TR为16位寄存器,存储局部描述符表段和任务段选择子,这是因为局部描述符表和任务段本身是作为全局描述符表的表项存在的,Windows操作系统可以同时存在多个局部段描述表和TSS任务段。如果需要访问局部段描述符表或TSS任务段可以使用LDT指令或LTR指令将段选择子存入LDTR和TR寄存器。

看到这里,读者可能会产生一些畏惧的情绪,Win32位系统寻址尽然如此复杂。如果你仅是一名Windows应用程序员,完全没必要担心。在应用程序的源程序中只需要使用32位的偏移地址就可以了。至于段基址和段权限这些内容都是使用操作系统默认值,应用程序的段基址通常为0,而段的大小是以页(4KB)为单位分配,在编译时由编译器更具源代码中分段的大小确定。至于段属性只能是R3特权级。接下来我们做一个实验。

实验一:查看32位应用程序的内存分配

打开DtDebug调试器,随便拖入一个32位应用程序,如图1-1所示。

【注】本机环境为X64处理器,Windows 10操作系统。

图1-1 观察段寄存器的值

●观察段寄存器的值

图中ES附加段寄存器的值为002BH,CS段寄存器的值为0023H,SS段寄存器的值为002BH,DS寄存器的值为002BH。这4个段寄存器的段选择子中的权限请求都是R3(低两位的值为3),表明当前进程的特权级为R3。FS段寄存器指向线程环境块,在32位程序中GS段寄存器通常用来指向TLS本地线程存储。

【注意】不同版本的Windows操作系统中默认的段寄存器的值可能会不同,但是其特权级一定是相同的。

●观察内存分配

图1-2 查看内存窗口

如图1-2所示,点击工具栏内存窗口“M”,在内存中可以清晰的看到当前进程HelloWord.exe的内存分配情况。在调试器中只显示低2GB空间的内存分配。Address一栏显示32位线性地址(每个段的基址),Size一栏显示内存分配大小(以4KB页为单位)。Owner一栏显示进程名称,Section一栏显示节区名(段名)。在低2GB空间的高地址处加载dll系统动态链接库。0x7FFF0000~0x7FFFFFFF和0~0xFFFF为禁止访问区域,其余空白空间为进程环境块、线程环境块、堆区和栈区。

如果读者想要更深入的学习Windows系统内核,请留意我们关于操作系统内核的课程。

●步骤二:将32位线性地址转换为物理地址

在转换之前首先需要考虑的是物理地址是多少位。如果物理内存小于4GB,那么物理地址使用32位就可以了。如果物理内存大于4GB,可以考虑使用36位,可以寻址的范围就是64GB了。剩下的问题就是如何将32位线性地址转换为32位或36位或者更多位的物理地址了。我们以小于等于4GB物理内存为例,对应的物理地址是32位,以4KB页为单位分配内存。我们可以按照10-10-12分页机制创建一个PageTable地址映射表。如图1-3所示,32位线性地址中的高10位为页目录表索引,32位线性地址中间10位为页表索引,32位线性地址低12位为偏移地址。创建进程初始化时创建了地址映射表,页目录表的物理基址存储在CR3寄存器中。

图1-3 10-10-12分页机制

转换公式:页目录表基址+PDI*4+PTI*4+12位偏移。

每个进程在初始化时都会创建一个CR3(准确的说是一个CR3的值,CR3本身是个寄存器,一个核,只有一套寄存器), CR3指向一个物理页就是页目录表,一共1024个表项(也就是1024个页表),每一项32位,共4096字节(4KB)。每一个页表中也有1024个表项,每一项都是一个32位的物理页基址。每一个页表是4KB大小,一共1024个页表(页目录表本身为其中一个页表),因此地址映射表一共占用4MB大小的空间,并且存储在高2GB空间中。我们将高2GB空间虚拟地址0xC0300000和CR3中存储的页目录表的物理页地址对应,将虚拟地址0xC0000000与页表的第0页对应,因此只需要使用虚拟地址0xC0300000或0xC0000000就可以直接访问地址映射表了。通过查表的方法将32位线性地址转换为32位物理地址。

以此类推,如果物理内存大于4GB,可以使用2-9-9-12分页机制建立地址映射表。也可以是其它类似的分页机制,只要可以正确访问物理地址就可以了。

 注意

       只有真正发生读写操作的时候,才需要查找地址映射表,访问物理内存。

       ■Win64操作系统:

       Windows 64位操作系统理论上可以访问的最大内存为264,但实际只使用了低48位,可以访问的248TB内存空间。Windows 64位操作系统寻址变得简单了,DS、CS、SS段寄存器不再需要,没有了分段机制,只保留了分页机制。Windows 64位系统采用9-9-9-9-12分页机制,如图1-4所示:

       Win64操作系统分页机制原理和Win32操作系统分页机制原理相同,此处不再赘述。

                                                        图1-4 9-9-9-9-12分页机制

1.3.2 虚拟内存

       上一小节我们讲述了4GB虚拟空间,这一小节我们讲解虚拟内存。很多读者无法正确区分虚拟内存和虚拟空间。

       ■虚拟空间

4GB虚拟空间是我们编写32位Windows应用程序的模板,我们在源程序中按照32位逻辑地址编写应用程序,程序可以访问的虚拟地址空间的大小为4GB。

虚拟内存

●分页机制

虚拟内存是和页交换机制密切相关的。早期的32位计算机的物理内存很小,可能只有512KB,后来随之集成电路的发展,物理内存逐渐扩大到1GB、2GB、4GB、8GB,今天32GB的物理内存已经是比较常用的了。32位应用程序按照4GB模板编写,随着应用程序的功能越来越复杂,程序的体积必然越来越大。而且Win32系统支持多任务,可以同时加载多个进程,这必然涉及到一个非常严峻的问题,物理内存不足。为了解决这个问题,Windows操作系统采用了分页机制和页交换机制。由于地址映射表的存在,我们可以通过映射机制(映射就是查表的意思)将虚拟地址转换为物理地址。Windows操作系统以4KB页为单位分配虚拟4GB空间,如图1-2所示,HelloWord.exe进程初始化时一共分配了4个页,其中PE头分配了一页,代码段.text分配了一页,.rdata节区分配了一页,数据段.data分配了一页。与此对应,物理内存足够分配4个对等的物理页,并将其填写到地址映射表中,与虚拟线性地址想对应。

●页交换机制

假设HelloWord.exe进程体积大小为4GB,再加上系统DLL、堆栈、进程环境块和线程环境块占用的内存空间,在低2GB虚拟空间中无法正常加载整个进程,只能先加载部分页。再假设物理内存只有512MB大小,在地址映射表中实际映射的物理页必然小于实际需要的物理页。为了保证已加载的页通过地址映射表可以正常访问物理内存,当前已加载的部分页(必定小于512MB)。当前已加载页执行完之后,后续的页由于未加载,引发缺页异常,Windows操作系统的异常处理程序将已执行过的页存储到物理磁盘上的页交换文件中,然后在装载将要访问的页面,并重新建立物理地址映射后继续执行。我们把这个过程称之为页交换机制。我们将磁盘上的交换文件和物理内存一并称之为虚拟内存,虚拟内存的大小=页交换文件的大小+实际物理内存的大小。实际情况是,操作系统同时加载了多个类型HelloWord.exe进程,实际需要的内存要大的多。接下来我们动手做一个实验为证。

实验二:查看虚拟内存和物理内存

打开任务管理器,如图1-5所示:

图1-5 任务管理器查看内存

图中显示当前机器物理内存为16GB,正在使用中的物理内存为5.8GB,剩余可以使用的物理内存为10GB。注意下方,已经提交的内存为17.6GB,已申请使用的内存为22.9GB,这里的内存已经超出物理内存16GB的大小,必定是指虚拟内存。

此外,我们还可以通过另外一种方式查看当前Windows系统的虚拟内存大小。在控制台窗口输入命令:systeminfo,查看当前机器信息如下所示:

C:\Users\16400>systeminfo

主机名:           DESKTOP-ENIJKEB

OS 名称:          Microsoft Windows 10 教育版

OS 版本:          10.0.16299 暂缺 Build 16299

OS 制造商:        Microsoft Corporation

OS 配置:          独立工作站

OS 构件类型:      Multiprocessor Free

注册的所有人:     暂缺

注册的组织:       暂缺

产品 ID:          00328-10000-00001-AA821

初始安装日期:     2018/12/22, 22:50:35

系统启动时间:     2023/11/21, 7:01:29

系统制造商:       MSI

系统型号:         MS-7A59

系统类型:         x64-based PC

处理器:           安装了 1 个处理器。

                 [01]: Intel64 Family 6 Model 158 Stepping 9 GenuineIntel ~4200 Mhz

BIOS 版本:        American Megatrends Inc. A.50, 2017/3/31

Windows 目录:     C:\Windows

系统目录:         C:\Windows\system32

启动设备:         \Device\HarddiskVolume1

系统区域设置:     zh-cn;中文(中国)

输入法区域设置:   zh-cn;中文(中国)

时区:             (UTC+08:00) 北京,重庆,香港特别行政区,乌鲁木齐

物理内存总量:     16,271 MB

可用的物理内存:   9,627 MB

虚拟内存: 最大值: 23,393 MB

虚拟内存: 可用:   4,847 MB

虚拟内存: 使用中: 18,546 MB

页面文件位置:     C:\pagefile.sys

域:               WORKGROUP

登录服务器:       \\DESKTOP-ENIJKEB

修补程序:         安装了 13 个修补程序。

                  [01]: KB4534129

                  [02]: KB4134661

                  [03]: KB4295110

                  [04]: KB4462930

                  [05]: KB4471331

                  [06]: KB4477136

                  [07]: KB4480979

                  [08]: KB4486153

                  [09]: KB4486155

                  [10]: KB4541731

                  [11]: KB4561600

                  [12]: KB4562560

                  [13]: KB4561602

网卡: 安装了 3 个 NIC。

                  [01]: VMware Virtual Ethernet Adapter for VMnet1

                      连接名:      VMware Network Adapter VMnet1

                      启用 DHCP:   是

                      DHCP 服务器: 192.168.194.254

                      IP 地址

                        [01]: 192.168.194.1

                        [02]: fe80::6c0e:7577:e534:10d6

                  [02]: VMware Virtual Ethernet Adapter for VMnet8

                      连接名:      VMware Network Adapter VMnet8

                      启用 DHCP:   是

                      DHCP 服务器: 192.168.76.254

                      IP 地址

                        [01]: 192.168.76.1

                        [02]: fe80::5d7b:2e73:7d56:c7f6

                  [03]: Intel(R) Ethernet Connection (2) I219-V

                      连接名:      以太网

                      启用 DHCP:   否

                      IP 地址

                        [01]: 192.168.2.105

                        [02]: fe80::4d62:17e6:4fc3:95a4

Hyper-V 要求:     虚拟机监视器模式扩展: 是

                  固件中已启用虚拟化: 是

                  二级地址转换: 是

                  数据执行保护可用: 是

【注意】页交换文件位置: C:\pagefile.sys

1.3.3 多任务切换

       ■DOS系统任务切换

回顾一下简单直白的DOS操作系统。DOS操作系统为单任务系统,处理器和操作系统本身并不支持多任务切换。聪明的程序员自己想办法实现了DOS系统的任务切换。当一个任务(进程)退出时,将其一部分程序驻留在内存中,然后通过热键激活驻留程序实现任务切换。还可以通过另外一种方式,设置一个时钟,到了指定时间执行特定的任务。这两种方式从本质上都是通过中断(键盘中断和时钟中断)实现任务切换。

       ■Windows系统任务切换

我们再看Windows操作系统是如何实现任务切换的。先明确一下什么是任务。在单核处理器时代,一个进程只有一个线程,任务等同于进程或线程。到了多核处理器时代,一个进程可以同时拥有多个线程,此时,任务特指线程,任务切换就是线程切换。

●Windows任务切换可以分为几种情形:

情形一:线程时间片到期,切换线程就绪队列中的新线程。

情形二:有了更高优先级的线程进入就绪队列,终止当前线程,切换到优先级高线程。

情形三:线程结束,自然退出。

情形四:强制结束当前线程。

线程切换时,需要将线程信息保存到线程环境块中,以备再次轮循执行。

●在应用程序中如何实现任务切换呢?32位处理器提供了几种任务切换的方法,包括调用门、中断门、陷阱门和中断门。而实际情况是,Windows操作系统只使用了陷阱门和中断门,部分使用了任务门,完全未使用调用门。不过作为程序员,可以利用处理器提供的所有方法实现任务切换。

作为Windows应用程序的开发者不必担心,任务切换的实现都是隐藏在现有的API函数调用中,只需掌握其调用方法就可以了。如果你是一个有追求的开发者,可以进一步深入学习,这里作者推荐《Windows核心编程》这本书经典的教科书,也可以参考编程达人关于保护模式的Windows内核相关的系列教材。 

本文摘自编程达人系列教材《Winwows API每日一练》。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/677090.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企业微信hook接口协议,ipad协议http,发送CDN语音消息

发送CDN语音消息 参数名必选类型说明uuid是String每个实例的唯一标识,根据uuid操作具体企业微信send_userid是long要发送的人或群idisRoom是bool是否是群消息 请求示例 {"uuid":"1753cdff-0501-42fe-bb5a-2a4b9629f7fb","send_userid&q…

树莓派4B 学习笔记3: 系统自动更新时间_测试CSI摄像头_安装OpenCv_4.6(未成功编译源码)_备份树莓派镜像

今日继续学习树莓派4B 4G:(Raspberry Pi,简称RPi或RasPi) 本文我只是安装了OpenCv 4.6,但编译源码失败了!有关 OpenCv 部分仅做笔记暂存! 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令…

平板显示LED背光芯片OC6700,输入3.6V~60V,升压型 LED 恒流驱动器

概述 OC6700是一款内置60V功率NMOS高效率、高精度的升压型大功率LED恒流驱动芯片。OC6700采用固定关断时间的控制方式,关断时间可通过外部电容进行调节,工作频率可根据用户要求而改变。OC6700通过调节外置的电流采样电阻,能控制高亮度LED灯的…

汇编:数据定义数据填充

数组的定义 在32位汇编语言中,定义数组时,通常使用定义数据指令(如 DB, DW, DD,DQ )和标签来指定数组的名称和内容。DB定义字节数组(每个元素占1字节)、DW定义字数组(每个元素占2字节&#xff…

【AI基础】第二步:安装AI运行环境

开局一张图: 接下来按照从下往上的顺序来安装部署。 规则1 注意每个层级的安装版本,上层的版本由下层版本决定 比如CUDA的版本,需要看显卡安装了什么版本的驱动,然后CUDA的版本不能高于这个驱动的版本。 这个比较好理解&#xff…

注意力机制篇 | YOLOv8改进之引入STA(Super Token Attention)超级令牌注意力机制 | CVPR2023

前言:Hello大家好,我是小哥谈。超级令牌注意力机制是一种基于Transformer的模型,用于处理长文本序列的任务。它通过引入超级令牌(Super Token)来减少输入序列中的填充标记,从而提高计算效率和模型性能。🌈 目录 🚀1.基础概念

1.4 Unicode简介

现在的Windows操作系统有许多不同语言版本,可以支持所有国家现有的语言文字。这就涉及到不同字符集的编码规则。 本节必须掌握的知识点: 字符集 C语言款字符 宽字符和Windows 1.4.1 字符集 ■ANSI多字节字符集 ●ASCII码 现代计算机发源于美国&…

一分钟了解香港的场外期权报价

香港的场外期权报价 在香港这个国际金融中心,场外期权交易是金融市场不可或缺的一部分。场外期权,作为一种非标准化的金融衍生品,为投资者提供了在特定时间以约定价格买入或卖出某种资产的机会。对于希望参与这一市场的投资者来说&#xff0…

RabbitMQ学习笔记(一)RabbitMQ部署、5种队列模型

文章目录 1 认识MQ1.1 同步和异步通讯1.1.1 同步通讯1.1.2 异步通讯 1.2 技术对比 2 RabbitMQ入门2.1 RabbitMQ单机部署2.2 RabbitMQ基本结构2.3 RabbitMQ队列模型2.3.1 简单队列模型(Simple Queue Model)2.3.2 工作队列模型(Work Queue Mode…

I.MX RT1170之MIPI DSI初始化和显示流程详解

MIPI DSI(Mobile Industry Processor Interface Display Serial Interface)是一种广泛应用于移动设备显示屏的接口标准。由MIPI联盟制定,DSI接口旨在提供高效、低功耗的显示屏数据传输解决方案。 本节来就通过学习I.MX RT1170单片机中的MIPI…

Vue3——实现word,pdf上传之后,预览功能(实测有效)

vue-office/pdf - npm支持多种文件(**docx、excel、pdf**)预览的vue组件库,支持vue2/3。也支持非Vue框架的预览。. Latest version: 2.0.2, last published: a month ago. Start using vue-office/pdf in your project by running npm i vue-office/pdf. There are …

英伟达开源新利器NV-Embed向量模型,基于双向注意力的LLM嵌入模型,MTEB 56项任务排名第一

前言 文本嵌入模型能够将文本信息转化为稠密的向量表示,并在信息检索、语义相似度计算、文本分类等众多自然语言处理任务中发挥着关键作用。近年来,基于解码器的大型语言模型 (LLM) 开始在通用文本嵌入任务中超越传统的 BERT 或 T5 嵌入模型&#xff0c…

Redis整合SpringBoot微服务基础操作

前言 首先我们先知道类似于JDBC的连接中间件在redis之间使用的是啥 首先是Jedis,这是最初代的连接redis客户端 操作也是非常的简单 Jedis 首先我们先介绍这个 我们只需要引入对应的pom文件依赖 <!--SpringBoot通用依赖模块--><dependency><groupId>org.spri…

uniapp使用uQRCode页面不显示也不报错

我使用的版本是&#xff1a;4.0.6 引入到项目中后根据官方的配置教程进行配置&#xff1a; 但是页面上就是不显示&#xff0c;也不报错&#xff0c;看官网发现步骤也没问题 解决方法&#xff1a; 这句话代表的是uQrcode会被自动引用注册&#xff0c;但是你引过组件库或者别的…

51单片机课设

1.51最小系统板原理图介绍 复位电路&#xff1a;&#xff08;简单的RC电路&#xff09; 在电路图中&#xff0c;电容的的大小是10uF&#xff0c;电阻的大小是10k。 当接通VCC后&#xff1a; 电容还没开始充电&#xff0c;电容电压为0&#xff0c;R7的电压为5V,然后电容开始充电…

盲盒小程序库存管理的关键策略

随着盲盒经济的兴起&#xff0c;越来越多的商家开始投入盲盒小程序的开发与运营。然而&#xff0c;在享受市场红利的同时&#xff0c;库存管理的问题也随之而来。合理的库存管理不仅能够满足用户需求&#xff0c;还能有效优化库存周转率&#xff0c;提升商家的盈利能力。本文将…

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(四)---- C语言与计算机架构(Programming xv6 in C)

系列文章目录 操作系统入门系列-MIT6.S081&#xff08;操作系统&#xff09;学习笔记&#xff08;一&#xff09;---- 操作系统介绍与接口示例 操作系统入门系列-MIT6.828&#xff08;操作系统工程&#xff09;学习笔记&#xff08;二&#xff09;----课程实验环境搭建&#x…

【图像识别系统】表情识别Python+人工智能深度学习+TensorFlow+卷积算法网络模型+图像识别

表情识别系统&#xff0c;本系统使用Python作为主要编程语言&#xff0c;通过TensorFlow搭建ResNet50卷积神经算法网络模型&#xff0c;通过对7种表情图片数据集&#xff08;‘Neutral’, ‘Anger’, ‘Disgust’, ‘Fear’, ‘Happy’, ‘Sad’, ‘Surprise’&#xff09;进行…

安装存储器的段描述符并加载GDTR

代码清单 ;代码清单12-1;文件名&#xff1a;c12_mbr.asm;文件说明&#xff1a;硬盘主引导扇区代码;创建日期&#xff1a;2011-5-16 19:54&#xff1b;修改于2022-02-16 11:15;设置堆栈段和栈指针mov ax, csmov ss, axmov sp, 0x7c00;计算GDT所在的逻辑段地址12 mov ax, [c…

视图的相关操作

4.1.1 创建视图 语法格式&#xff1a;create [ or replace ] view view_name [ ( column_list ) ] as select_statement [ with [ cascade | local ] check option ] 说明&#xff1a; &#xff0…