您的位置:首页 > 其它

Windows 内存管理方法(一)

2015-03-12 16:10 176 查看


两个内存:

物理内存——就是插在主板上的内存条,它是固定的,内存条的容量多大,物理内存就有多大(集成显卡系统除外),但是如果程序运行很多或者程序本身很大的话,就会导致大量的物理内存占用,甚至导致物理内存消耗殆尽。

虚拟内存——虚拟内存就是在硬盘上面划分一块页面文件,充当内存。当程序在运行的时候,有一部分资源还没有用上或者同时打开几个程序却只能操作其中一个程序时,系统没必要将程序所有的资源都塞在物理内存中,所以紫铜个暂时将这些不用的资源放在虚拟内存里面,等到需要的时候再调用。


三个地址:

物理地址(physical address)——用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。内存并不是通过物理地址的方式来寻址的,(虽然可以直接把物理地址理解成插在机器上的内存本身,把内存看成一个从0直接一直到最大空间逐字节编号的大数组,然后把这个数组叫做物理地址),说它是“与地址总线相对应”还更贴切一些。

使用物理地址访问内存的方式成为 实地址方式

逻辑地址(logical address)——是指由程序产生的与段相关的偏移地址部分。例如,你在进行c语言指针编程的过程中的&操作,取得的就是逻辑地址,它是相对于你当前进程数据段的地址,不和绝对物理地址相干。只有在Intel实模式下,逻辑地址才和物理地址相等(因为实模式没有分段或者分页,cpu不进行自动地址转换),逻辑地址也就是在Intel保护模式下程序执行代码段限长内的偏移地址,(假定代码段、数据段如果完全一样)。应用程序员仅仅需要与逻辑地址打交道,而分段和分页是对程序员完全透明的,仅仅由系统编程人员涉及。应用程序员虽然自己可以直接操作内存,也只能在操作系统给你分配的那段内存来操作。

使用逻辑地址访问内存的方式成为 分段内存方式

Intel为了兼容,保留了之前的段式内存管理方式,逻辑地址是机器语言指令用用来指定一个操作数或者是一条指令的地址,一个逻辑地址=段标识符+段内偏移量

逻辑地址是程序源码编译后所形成的跟实际内存没有直接联系的地址,即在不同的机器上,使用相同的编译器来编译同一个源程序,则其逻辑地址是相同的,但是相同的逻辑地址,在不同的机器上运行,其生成的线性地址又不相同。源码编译后生成的地址,只是偏移的地址,而形成逻辑地址的[段基址:偏移地址]中的段基址,是在生成任务时才定下来的,也就是说,[段基址:偏移地址]只有在进程中才会用到,在程序中只有偏移地址的概念

线性地址(linear address)/虚拟地址(virtual
address)——与逻辑地址类似。它也是一个不真实的地址,如果逻辑地址是对应的硬件平台段式管理转换前地址,那么线性地址就对应了硬件页式内存的转换前地址。windows采用页式内存管理方案,在intel
x86 处理器上,windows不使用段来管理虚拟内存,但是 intel
x86处理器在访问内存时必须要通过段描述符,这意味着windows将所有的段描述符都构造成了从基地址0开始,且段的大小设置为0x
80000000
0xc00000000xffffffff,具体取决于段的用途和系统设置。0x80000000是32位windows的系统空间开始处,0xc0000000
是页目录表的开始处 同时也是64位windows系统空间的开始处。windows系统中的代码,包括操作系统本身和应用程序代码,所面对的地址空间都是线性地址空间,这种做法屏蔽了处理器中的逻辑地址概念,段只用于访问控制和内存保护

使用线性地址访问内存的方式成为 平坦内存方式

Ps:cpu工作的三个模式(从Intel开发80386以后的计算机都具有)

1) 实模式(实地址工作模式|real
mode)——是最基本的工作方式,实地址模式与16位微处理器8086/8088的实地址模式保持兼容,原有的16位微处理器的程序不加任何修改就可以再80486的微处理器实地址模式下面运行,80486处理器的实地址模式具有更强的功能,增加了寄存器,扩充了指令,可以进行32位操作。

8086/8088只能工作于实模式,80286及以上的微处理器可以工作于实模式、保护模式和虚拟8086模式。

实模式操作方式只允许微处理器寻址第一个1MB存储空间,(8086CPU数据总线16位,也就是一次最多能取2^16=64KB数据,这个数据也解释了实模式下为什么每个段最大只有64KB。但刚才还说了其地址总线为20,这样它能寻址的能力其实是2^20=1MB,这也就是实模式下CPU的最大寻址能力。)存储器中第一个1MB存储单元成为实模式存储器或者常规内存,Dos操作系统要求微处理器工作于实模式,当80486微处理器工作于实地址模式时,存储器的管理方式与8086微处理器存储器的管理方式完全相同

2) 保护模式(保护工作模式|protected
vrirtual address mode)——特点是引入了虚拟内存的概念,同时可以使用附加的指令集,所以80486支持多任务操作,在保护模式下,80486微处理器可访问的物理存储空间为4GB(232),程序可用的虚拟存储空间为64TB(246)(TI用来指明全局描述符表GDT还是局部描述符表LDT,RPL表示请求特权级,索引值为13,所以从这里看出,在保护模式下最多可以表示2^13=8192个段描述符,而TI又分GDT和LDT(如图3所示),所以一共可以表示8192*2=16384个段描述符,每个段描述符可以指定一个具体的段信息,所以一共可以表示16384个段。而图1看出,段内偏移地址为32位值,所以一个段最大可达4GB,这样16384*4GB=64TB)。

保护模式通常是为了防止下列情况的发生:

a. 应用程序破坏系统程序;

b. 某一应用程序破坏了其它应用程序;

c. 错误地把数据当做程序运行。

保护模式下的存储器寻址(80286及其以上的微处理器)允许访问第一个1MB及其以上的存储器内的数据和程序,寻址这个扩展的存储器段,需要更改用于实模式存储器寻址的段基址加上偏移地址的机制

在保护模式下,当寻址扩展内存里的数据和程序时,仍然使用偏移地址访问位于存储段内的信息。区别是,实模式下的段基址段寄存器提供,而保护模式下的段寄存器里存放着一个选择符(selector),用于选择描述表内的一个描述符,描述符(descriptor)描述存储器段的位置、长度和访问权限。由于段基址加偏移地址仍然用于访问第一个1MB存储器内的数据,所以保护模式下的指令和实模式下的指令完全相同。

保护模式和实地址模式的不同之处在于存储地址空间的扩大(由1MB扩展到4GB),以及存储器管理机制的不同。

保护模式同实模式的根本区别是进程内存受保护与否。可寻址空间的区别只是这一原因的果。实模式将整个物理内存看成分段的区域,程序代码和数据位于不同
区域,系统程序和用户程序没有区别对待,而且每一个指针都是指向"实在"的物理地址。这样一来,用户程序的一个指针如果指向了系统程序区域或其他用户程序 区域,并改变了值,那么对于这个被修改的系统程序或用户程序,其后果就很可能是灾难性的。为了克服这种低劣的内存管理方式,处理器厂商开发出保护模式。这 样,物理内存地址不能直接被程序访问,程序内部的地址(虚拟地址)要由操作系统转化为物理地址去访问,程序对此一无所知。

至此,进程(这时我们可以称程序 为进程了)有了严格的边界,任何其他进程根本没有办法访问不属于自己的物理内存区域,甚至在自己的虚拟地址范围内也不是可以任意访问的,因为有一些虚拟区 域已经被放进一些公共系统运行库。这些区域也不能随便修改,若修改就会有: SIGSEGV(linux
段错误);非法内存访问对话框(windows 对话框)。

CPU启动环境为16位实模式,之后可以切换到保护模式。但从保护模式无法切换回实模式

3) 虚拟8086工作模式——80486微处理器允许在实地址模式和虚拟8086(virtual
8086 mode)模式下执行8086的应用程序,虚拟8086模式为系统设计人员提供了80486微处理器保护模式的全部功能,因而具有更大的灵活性,有了虚拟8086模式,允许80486微处理器同时执行8086操作系统和8086应用程序,以及80486微处理器操作系统和80486微处理器的应用程序。因此,在一台多用户的80486微处理器的计算机里,多个用户可以同时使用计算机。

在虚拟8086模式下,还可以用与实地址模式相同的形式应用段寄存器,而形成现行基地址。通过使用分页功能,就可以把虚拟8086模式下的1MB地址空间映像到80486微处理器的4GB物理空间中的任何位置。


三个内存的转换方式:

每个进程有4GB的虚拟地址空间,每个空间都做了如下划分:

a. 一部分映射物理内存

b. 一部分映射硬盘上的交换文件

c. 一部分什么也不做

程序中都是使用4GB的虚拟地址,访问物理内存需要使用物理地址,物理地址是放在寻址总线上的地址,以字节(8位)为单位。

Cpu将一个虚拟内存空间中地址转换为物理地址,需要进行两步:

1. 将给定的一个逻辑地址(即段内偏移量)利用cpu的段式内存管理单元,转换成一个线性地址,

2. 然后利用其页式内存管理单元,转换为最后的物理地址。


页表\页目录概念

虚拟地址由操作系统维护,由mmu(内存管理单元)可以进行转换,扩大了内存空间分页管理。大多数使用虚拟存储器的系统都使用一种称为分页(Paging)机制。采用分页机制的系统,虚拟地址空间以页面为单位进行划分,虚拟地址空间会被划分为多个等大小的页面。物理地址空间也按照页面为单位进行划分每一块成为页帧,或者页框。每一虚拟页面可以随意对应到物理页框,也可以对应到磁盘的页面文件上。(按照IA32的分页机制来说,标准页面大小为4k。

以下面的指令作为例子:

Mov指令: mov eax,[0]

此时虚拟地址0将被发给MMU,MMU发现0属于页面0的范围内,如果页面0对应的页框号为1,那么物理地址就在4096-8191范围内,此时就会将4096发送到地址总线上。因为虚拟地址0的页内偏移也是0(页内偏移:在页面里的位置,比如1,页面偏移死1,4097的页面偏移也是1,这是因为一个页面大小为4K,用虚拟地址mod
4K就得到了页内偏移


上面的是虚拟地址到物理地址的映射的简单情况,但是在记录这些页面到页框的映射关系的时候(当然有些处理器是页框到页面的转化),在IA处理器上面使用的是页表,就是在物理内存里面有一块连续的空间,来记录这些页面到页框的映射关系,每一个页表项里面都有一部分去指向页框的起始地址,还有部分记录了这个页面的属性。可以通过页面号来做索引。页面号就是虚拟地址/4k得到的整数部分。如果只是单一的页表,也是有问题的,如果虚拟地址空间过大,那么页表所占的空间也会很大,这时候可以采用多级页表。IA32在采用4K页面的时候就使用了2级页表,IA64使用了四级。

使用了分页机制以后,4G的地址空间被分成了固定大小的页,每一页或者被映射到物理内存,或者被映射到硬盘上的交换文件中,或者没有映射任何东西,对于一般程序员来说,4G的地址空间,只有一小部分映射了物理内存,很大部分都是没有映射任何东西的。物理内存也被分页,来映射地址空间。对于32bit的win2k,页的大小是4k字节。CPU用来把虚拟地址转化成物理地址的信息存放在叫做页目录和页表的结构里。

物理内存分页,一个物理页的大小为4K字节,第0个物理页从物理地址0X00000000处开始,由于页的大小是4kb,就是0x1000字节,所以第一页从物理地址0X00001000处开始,第2页从物理地址0X00002000处开始。可以看到由于页的大小是4kb,所以需要32bit的地址中高20bit来寻址物理页。(4G/4k=2^20)

页目录:一个页目录大小为4K字节(2^20),放在一个物理页中.由1024个4字节的页目录组成(因为是win32),页目录中的每一项内容(每项4个字节)高20bit用来放一个页表(页表放在一个物理页中)的物理地址,低12bit放着一些标志。

页表:一个页表的大小为4K字节,放在一个物理页中,由1024个4字节的页表项组成,页表项的大小为4字节(32bit),所以页表中有1024个页表项,页表中每一项的内容(每项4个字节,32bit)高20bit用来放一个物理页的物理地址,低12bit放着一些标志。

对于x86系统,页目录的物理地址放在cpu的CR3寄存器中。


虚拟地址转换成物理地址

一个虚拟地址大小为4字节,其中包含找到物理地址的信息,虚拟地址分为3个部分:

1) 31-22位(10位)是页目录中的索引;

2) 21-12位(10位)是页表中的索引;

3) 11-0位(12位)是页内偏移

转换过程:

首先通过CR3找到页目录所在的物理页——》根据虚拟地址中的31-22找到该页目录项——》通过该页目录项找到该虚拟地址对应的页表地址——》根据虚拟地址21-12找到物理页的物理地址——》根据虚拟地址的11-0位作为位偏移加上该物理页的地址就找到了该虚拟地址对应的物理地址。

CPU把虚拟地址转换成物理地址:一个虚拟地址,大小4个字节(32bit),包含着找到物理地址的信息,分为3个部分:第22位到第31位这10位(最高10位)是页目录中的索引,第12位到第21位这10位是页表中的索引,第0位到第11位这12位(低12位)是页内偏移。对于一个要转换成物理地址的虚拟地址,CPU首先根据CR3中的值,找到页目录所在的物理页。然后根据虚拟地址的第22位到第31位这10位(最高的10bit)的值作为索引,找到相应的页目录项(PDE,page
director entry ),页表项中就有这个虚拟地址所对应物理页的物理地址。最后用虚拟地址的最低12位,也就是页内偏移,加上物理页的物理地址,就得到了该虚拟地址所对应的物理地址。

一个页目录有1024项,虚拟地址最高的10bit刚好可以索引1024项(2的10次方等于1024)。一个页表也有1024项,虚拟地址中间部分的10bit,刚好索引1024项。虚拟地址最低的10bit(2的12次方等于4096,作为页内偏移,刚好可以索引4kb,也就是一个物理页中的每个字节)。

每个进程都有自己的4G空间,从0X00000000~0XFFFFFFFF。通过每个进程自己的一套页目录和页表来实现。由于每个进程有自己的页目录和页表,所以每个进程的地址空间映射的物理内存是不一样的。两个进程的同一个虚拟地址处(如果都有物理内存映射)的值一班是不同的,因为ietamen往往对应不同的物理页。

4G地址空间中低2G,0X00000000-0X7FFFFFFF是用户地址空间,4G地址空间中高2G,即0X80000000-0XFFFFFFFF是系统地址空间。访问地址空间需要程序有ring()的权限。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: