• 计算机系统中虚拟内存概念解疑(1)


    处理器遇到的地址都是虚拟地址,虚拟地址和物理地址都分成页码(页框)和偏移量俩部分组成。在虚拟地址转换成物理地址的过程中,偏移值不变,而页码和页框码之间的映射就在一个映射记录表——页表中

    当进程创建时,内核为进程分配4G虚拟内存,此时,仅仅只是建立一个映射关系,程序的数据和代码都还在磁盘中,只有当运行时才换回物理内存。并且,通过malloc来分配动态内存时,也只分配了虚拟内存,并不会直接给物理内存,因此,理论上来说malloc可分配的内存大小应该是无限制的(实际当然会有很多算法进行限制)。

    在最开始看书的时候,我知道程序在运行时,不是全部加入内存当中的,当然,这个现在依旧正确,在有了虚拟地址空间这个概念以后,我一直认为是在硬盘中划分出一块虚拟内存出来,然后给每个程序4G的硬盘空间,作为这个程序的虚拟内存,然后就需要运行哪一块然后哪一块装入内存当中。后来发现这个是错误的。大家可以在我错误的地方来看看自己的理解,纠正自己的问题。

        首先,虚拟地址空间是不等于虚拟内存的(我的一本Linux教材上写的是这两个概念一致的,我认为是错误的)。我们来看一下这几个概念:

        虚拟内存:虚拟内存是一种逻辑上扩充物理内存的技术。基本思想是用软、硬件技术把内存与外存这两级存储器当做一级存储器来用。虚拟内存技术的实现利用了自动覆盖和交换技术。简单的说就是将硬盘的一部分作为内存来使用。

        虚拟地址空间:在32位的i386 CPU的地址总线的是32位的,也就是说可以寻找到4G的地址空间。我们的程序被CPU执行,就是在0x00000000到0xFFFFFFFF这一段地址中。高2G的空间为内核空间,由操作系统调用,低2G的空间为用户空间,由用户使用。

        CPU在寻址的时候,是按照虚拟地址来寻址,然后通过MMU(内存管理单元)将虚拟地址转换为物理地址。因为只有程序的一部分加入到内存中,所以会出现所寻找的地址不在内存中的情况(CPU产生缺页异常),如果在内存不足的情况下,就会通过页面调度算法来将内存中的页面置换出来,然后将在外存中的页面加入到内存中,使程序继续正常运行。

      可以看出,虚拟地址空间和虚拟内存的一个关键的因素是MMU(内存管理单元)。

        现在一个程序的执行现在可以分为3部分:

        1:CPU需要执行的语句的虚拟地址。

        2:程序装入内存的部分

        3:程序再外存中的部分

        因为CPU是通过时间片轮转的方法使不同的程序并发执行的。所以在某一时刻只有一个程序占据CPU资源,CPU的最大的寻址空间为4G,所以说可以将每个程序可以看做独立占据4G的内存(只是可以看成,但是它并没有占据实际的4G内存)。而CPU是将虚拟地址空间里面的代码执行,如果在内存中寻找不到所需要的页面,就需要到外存中寻找,外存的这一部分,我们可以当成内存来使用,这也就是虚拟内存。虚拟地址空间不等于虚拟内存。虚拟地址空间是一个空间,不是真正存在的,只是通过CPU的寻址虚拟出来的一个范围。而虚拟内存是实实在在的硬盘的空间。

        我看到了一个比较形象的比喻,假设4G个门牌号(4G的虚拟地址空间,并将这4G的虚拟空间进行分页),但是房子的数量(内存)少于门牌号的数量(4G的虚拟空间),那样就先把每个房子(内存)上挂一个门牌号(页),如果你要找一个门牌号(页),就需要查找每个房子(内存),如果这个门牌号没有挂(页还没有被加入到内存中),那么就将一个房子的门牌号(页面置换到外存)摘下来,把你找的那个门牌号挂上(将外存的页加入内存),这样就找到了需要的门牌号(页)。

        这是我将这个比喻综合了一下。CPU只需要说找哪一个页面,MMU就将这个页面翻译成物理地址,再通过页面调度机制来讲不在内存中的页加入到内存中。

        我认为计算机使用的是一种各司其职的方法。

        CPU老大只需要要虚拟地址中的一页,范围在0x00000000到0xFFFFFFFF,因为他的地址总线是32位,4G是他最大的能力,然后他就把任务分配给他的手下,CPU不需要知道他的手下是如何找到这一页,他只负责去要这一页和执行这些代码,然后他就和他的手下说“有招想去,没招死去”,他的手下必须要能找到这一页,然后内存非常有限,而CPU不管这个,只需要你能找到这一页让我执行就好,所以CPU的手下就将硬盘中的一部分当做内存,然后拿来骗CPU说,“这是我从内存中找到的”,然后CPU就去运行。如果访问的地方实在是不能找到,或者是没有权限,那么这个程序就真死了。程序员在开发的时候,因为程序员所编写的代码最终是要让CPU去执行,所以程序员也理所应当认为我有4G的内存空间,程序员把程序交给CPU,CPU就交给他手下。

        所以说,他们每一层都不需要管对方是如何办到的,他们在乎的只有结果。他们各司其职,CPU认为我有4G内存空间的原因是因为CPU的地址总线为32位,最大的寻址能力是4G,而内存没有这个大,所以它想出来的办法是将硬盘的一部分拿来骗CPU,并给这块骗人的地方起了一个好名字,虚拟内存。这就是我的理解中的虚拟内存空间和虚拟内存的概念。

    /********************************************************************************

    虚拟内存别称 虚拟存储器 (Virtual Memory)。 电脑 中所运行的

    程序均需经由 内存执行,若执行的程序占用内存很大或很多,则会导致内存消耗殆尽。为解决该问题, Windows中运用了虚拟 内存技术,即匀出一部分硬盘空间来充当内存使用。当内存耗尽时,电脑就会自动调用硬盘来充当内存,以缓解内存的紧张。若计算机运行程序或操作所需的 随机存储器RAM)不足时,则 Windows 会用 虚拟存储器进行补偿。它将计算机的 RAM和 硬盘上的临时空间组合。当RAM运行速率缓慢时,它便将数据从RAM移动到称为“ 分页文件”的空间中。将数据移入 分页文件可释放RAM,以便完成工作。 一般而言,计算机的RAM 容量越大,程序运行得越快。若计算机的速率由于RAM可用空间匮乏而减缓,则可尝试通过增加虚拟内存来进行补偿。但是,计算机从RAM读取数据的速率要比从硬盘读取数据的速率快,因而扩增RAM 容量(可加 内存条)是最佳选择。

    虚拟内存是Windows 为作为内存使用的一部分硬盘空间。虚拟内存在硬盘上其实就是为一个硕大无比的文件,文件名是 PageFile.Sys,通常状态下是看不到的。必须关闭资源管理器对系统文件的保护功能才能看到这个文件。虚拟内存有时候也被称为是“页面文件”就是从这个文件的文件名中来的。

    内存在计算机中的作用很大,电脑中所有运行的程序都需要经过内存来执行,如果执行的程序很大或很多,就会导致内存消耗殆尽。为了解决这个问题,WINDOWS运用了虚拟内存技术,即拿出一部分硬盘空间来充当内存使用,这部分空间即称为 虚拟内存,虚拟内存在硬盘上的存在形式就是 PAGEFILE.SYS这个页面文件。

    NT/2000的每一个进程都在启动时分配了4GB(0xFFFFFFFF)的虚拟内存。其中的某些部份实际上是由所有进程共享的,例如核心和设备驱动程序区域。但它们都会被映射到每个进程的虚拟地址空间里。实际上没有进程分配到4GB的物理内存,而是仅当需要时才分配物理内存。因此每一个进程都有各自的4GB虚拟内存,编址范围从0x00000000到0xFFFFFFFF。其中,0x00000000-0x0000FFFF是为NULL指针分配而保留的。访问该区域内存将导致“非法访问”错误。0x00010000-0x7FFEFFFF是用户进程空间。EXE文件的映像被加载到其中(起始地址0x00400000),DLL(动态链接库)也被加载到这部份空间。如果DLL或EXE的代码被装入到该范围的某些地址,就能够被执行。访问该区域中没有代码装入的地址将导致“非法访问”错误。0x7FFF0000-0x7FFFFFFF是保留区域,对此区域的任何访问都将导致“非法访问”错误。0x80000000-0xFFFFFFFF仅供操作系统使用。用于加载设备驱动程序和其它核心级代码。从用户级应用程序(ring 3)访问此区域将导致“非法访问”错误。

    虚拟内存可以说是两个不同的概念。从编程的角度来说,每个应用程序运行在独立的寻址空间,由操作系统通过页表机制,映射到真正的物理内存上边。程序请求内存时,如果请求不到指定大小的连续内存,就会报错。题主的问题应该就是这种情况 另一种概念是交换文件,也就是Linux swap的概念。内存访问速度快,但容量有限的,操作系统会把暂时用不到的内存数据,以文件的形式写到硬盘,节省的空间用来存储更多的必要数据。虚拟空间可以提高使用体验,但是有一种情况要注意,如果应用程序运行需要5G的内存,而机器只有4G内存,操作系统需要不停的将数据在内存和硬盘之类写入写出,体验很差。结论是,能加内存加内存,能上固态上固态。



    虚拟内存可以说是两个不同的概念。从编程的角度来说,每个应用程序运行在独立的寻址空间,由操作系统通过页表机制,映射到真正的物理内存上边。程序请求内存时,如果请求不到指定大小的连续内存,就会报错。题主的问题应该就是这种情况 另一种概念是交换文件,也就是Linux swap的概念。内存访问速度快,但容量有限的,操作系统会把暂时用不到的内存数据,以文件的形式写到硬盘,节省的空间用来存储更多的必要数据。虚拟空间可以提高使用体验,但是有一种情况要注意,如果应用程序运行需要5G的内存,而机器只有4G内存,操作系统需要不停的将数据在内存和硬盘之类写入写出,体验很差。结论是,能加内存加内存,能上固态上固态。








    因为windows进程间共享数据是用内存映射文件实现的,包括RPC、COM、OLE、DDE、DDE、WINDOWS消息、剪贴板、套接字等最底层的机制就是内存映射文件。


    所以要是不用业交换文件来实现进程间通信难道用临时磁盘文件实现吗


    题主你还没有搞清楚页面文件(交换空间)与虚拟内存的正确含义,我想你是想表达,为什么大内存还要设置页面文件?事实上,大内存根本无需设置页面文件,尤其是大于8G的情况下,页面文件是以前内存小的一个不得已的解决方案,用硬盘的一块空间来当作内存使用。操作系统把处于不活跃的进程所占用的内存页保存到硬盘上,留出更多的内存给活跃的进程使用,这样做的后果就是,由于硬盘速度很慢,尤其是机械硬盘,使得当这些不活跃的程序激活的时候,操作系统需要大量读写硬盘,造成系统响应速度严重下降!如今内存容量已不再是瓶颈,题主应该仔细看看是哪些用不上的进程占用了宝贵的系统资源,及时清理后台资源,把有限的资源用在正在使用的程序上才是硬道理。页面文件可以一时用来救急,如果你一直需要开启页面文件,那么就应当考虑增加物理内存,并在物理内存足够的情况下关闭页面文件,否则你的灵感将会消失在系统的卡顿和等待中!




    一个应用程序为什么会使用内存同时有使用虚拟内存呢
    楼主,你这个问题。。。。问的有点让人无语。。。。
    应用程序(我以游戏为主,因为通常一般程序是不会占用很多虚拟内存的)
    如果计算机缺少运行程序或操作所需的随机存取内存 (RAM),则 Windows 使用虚拟内存)进行补偿。 不知楼主有没有发现,在Windows2000(XP)目录下有一个名为pagefile.sys的系统文件,它的大小经常自己发生变动,小的时候可能只有几十兆,大的时候则有数百兆,这种毫无规律的变化实在让很多人摸不着头脑。其实,pagefile.sys是Windows下的一个虚拟内存,它的作用与物理内存基本相似,但它是作为物理内存的“后备力量”而存在的,但是,它并不是在只有物理内存不够用时才发挥作用的,也就是说在物理内存够用时也有可能使用虚拟内存,如果你虚拟内存设置过小则会提示“虚拟内存不足”。










    Windows内存结构梳理
    多字节数据是按怎样的顺序存放的呢?实际情况和CPU有关,微处理中的存放顺序有正序和逆序之分。正序(big-endian) 逆序(little-endian)
        两种编码的区别:
         big-endian:高位字节存入低字节,低位字节存入高地址,一次排列
         little-endian:低位字节存入低地址,高位字节存入高地址。反序排列
     
       unicode是asc字符编码的一个扩展,只不过在WINDOWS中,用两个字节对其进行编码,也称为宽字符集
       unicode中,所有的字符都是16位,包括所有的7为asc码都被扩充为16位(注意高位扩充的是〇)
       intel处理器在内存中,一个字存入存储器要占有相继的两个字节,这个字存放时就按little-endian方式存入,即低位字节存入低地址,高位字节存入高地址
      
       API函数,这些函数提供应用程序运行所需要的窗口管理、图形设备接口、内存管理等各项服务功能。这些功能以函数库的形式组织在一起,形成饿了WINDOWS应用程序编程接口(API),简称win api。win api子系统负责将api调用转换成WINDOWS操作系统的系统服务调用,所以,可以认为API函数是构筑整个WINDOWS框架的基石,在他的下面是WINDOWS的操作系统核心,而在他的上面则是WINDOWS应用程序,对于应用程序开发人员而言,所看到的WINDOWS操作系统实际上就是win API,操作系统的其他部分对开发人员来说是完全透明的
       WINDOWS运转的核心是一个称作“动态链接”的概念,WINDOWS提供了应用程序可利用的丰富的函数调用,这些函数采用动态链接即DLL实现
       win32API 是一个基于c语言的接口,但是win32API中的函数可以由用不同语言编写的程序调用,只要在调用时遵循调用的规范即可
       
        API函数是区分字符集的:A表示ANSI;W表示Widechars,即unicode。前者是通常使用的单字节方式,后者是宽字节方式,以便处理双字节字符。
       
        句柄是WINDOWS标识,由应用程序建立或使用的对象所使用的一个唯一的整数值(通常是32位)。WINDOWS要使用各种各样的句柄来标识诸如应用程序实例、窗口、图标、菜单、输出设备、文件等对象。程序通过调用WINDOWS函数获取句柄,然后在其他WINDOWS函数中使用这个句柄,以引用他代表的对象。句柄的实际值对程序来说无关紧要,这个值是被WINDOWS模块内部用来引用相应对象的
         当一个进程被初始化时,系统要为他分配一个句柄表,句柄值是放入进程的句柄表中的索引
         unicode影响到计算机工业的每个部分,对操作系统和编程语言的影响最大
         在NT架构下,win32API能接受unicode和ASCI字符串,而其内核则只能使用unicode ,所有这些操作对用户来说都是透明的,但进行这些字符串的转换需要占用系统资源。
        
         WINDOWS是一个消息驱动式系统,WINDOWS消息提供应用程序与应用程序之间、应用程序与WINDOWS系统之间进行通信的手段。应用程序想要实现的功能由消息来触发,并且靠对消息的响应和处理来完成。
         WINDOWS系统中有两种消息队列:一种是系统消息队列,另一种是应用程序消息队列。计算机的所有输入设备由WINDOWS监控。当一个事件发生时,WINDOWS先将输入的消息放入系统消息队列中,再将输入的消息拷贝到相应的应用程序队列中,应用程序中的消息循环从他的消息队列中检索每个消息并且发送给相应的窗口函数中。一个事件的发生,到达处理他的窗口函数必须经历上述过程。值得注意的是消息的非抢先性,即不论事件的急与缓,总是按到达的先后顺序排队(一些系统消息除外)
         由于WINDOWS本身是由消息驱动的,所以调试程序时跟踪一个消息会得到相当底层的答案。
         一般来说,80X86及其以后的各代CPU可在实模式、保护模式、虚拟86模式下运转
         在保护模式下程序可以利用更多的内存,可以实现多任务系统
         在保护模式下,CPU的寻址方式与实模式不同,实模式下的寻址方式是“段基址+段偏移”,段的默认大小为64kB,所有段都是可读/写的,唯有代码段是可执行的,段的特权级为0.而在保护模式下内存是“线性”的,因为这时段寄存器的意义不同,他里面存放的不再是段基地址,二十存放着段选择子,这呃值是不直接参与寻址的,只是全局描述表(global descriptor table ,GDT)或本地描述表(local descriptor table,LDT)的一个指针,不同段寄存器有不同的属性(读、写、执行、特权级等)
         虚拟内存(virtual memory)不是真正的内存,他通过映射(map)的方法,使可用的虚拟地址达到4GB,每个应用程序可以被分配2GB的虚拟地址,剩下的2GB留给操作系统自己用。WINDOWS是一个分时多任务操作系统,CPU时间被分成一个个的事件片后分配给不同程序,在一个时间片里,和这个程序执行不无关的东西并不映射到线性地址中。因此每个程序都有自己的4GB寻址空间,互补干扰。在物理内存中,操作系统和系统DLl代码需要供每个应用程序调用,所以在所有的时间必须映射;用户exe程序只在自己所属的时间片内被映射,而用户DLL则有选择地被映射。
       简单地说,虚拟内存的实现方法和过程如下:
    1、当一个应用程序被启动时,操作系统就创建一个新进程,并给每个进程分配2GB的虚拟地址(不是内存,只是地址)
    2、虚拟内存管理器将应用程序的代码映射到那个应用程序的虚拟地址中的某个位置,并把当前所需要的代码读取到物理地址中(注意:虚拟地址和应用程序代码在物理内存中的位置是没有关系的)
    3、如果使用动态链接库DLL,DLL也被映射到进程的虚拟地址空间,在需要的时候才被读入物理内存
    4、其他项目(例如数据、堆栈)的空间是从物理内存中分配的,并被映射到虚拟地址空间中
    5、应用程序通过使用他的虚拟地址空间中的地址开始执行,然后虚拟内存管理器把每次的内存访问映射到物理位置


       关于虚拟内存,要明白一下几点:
    1、应用程序是不会直接访问物理地址的
    2、虚拟内存管理器通过虚拟地址的访问请求,控制所有的物理地址访问
    3、每个应用程序都有相互独立的4GB寻址空间,不同应用程序的地址空间是隔离的
    4、DLL程序没有自己的“私有”空间,他们总是被映射到其他应用程序的地址空间中,作为其他应用程序的一部分运行。因为如果他不和其他程序同属一个地址空间,应用程序就无法调用他
       使用虚拟内存的好处是:简化了内存的管理,并可弥补物理内存的不足;可以防止多任务环境下各个应用程序之间的冲突
          在保护模式下,所有的应用程序都有权限级别,这个权限级别按优先次序分为4等
          0等级权限可以执行所有的指令并访问所有数据,操作系统核心层是运行在ring0级的,而win32子系统(如动态链接库)是运行在ring3级的,以提供与应用程序的接口
          保护模式使应用程序没有权限去破坏操作系统,只能规矩地使用win32API接口函数与系统打交道。如果想控制系统,就必须取得0特权级,比如调试工具softICE就是工作在0特权级上的
       
       WINDOWS的可执行文件(EXE、DLL)是PE格式
          PE文件使用的是一个平面地址空间,所有代码和数据都被合并在一起,组成一个很大的结构。文件的内容被分割为不同的区块(section,又称区段、节等),块中包含代码或数据。每个块都有他自己在内存中的一套属性,比如:这个块是否包含代码、是否只读或可读/写等
       每个块都有不同的名字,这个名字用来表示区块的功能。常见的快的有.text,.rdata,.data,.idata,.rsrc等。各种块的含义如下:
       .text:实在编译或汇编结束时产生的一种块,他的内容全是指令代码;
       .rdata:是运行期只读数据;
       .data:是初始化的数据块;
       .idata:包含其他外来的DLL的函数及数据信息,即输入表;
       .rsrc:包含模块的全部资源,如图标、菜单、位图等。
          PE文件非常好的一个地方就是在磁盘上的数据结构与在内存中的结构是一致的,装载一个可执行文件到内存中,主要就是将一个PE文件的某一部分映射到地址空间中。这样,PE文件的数据结构在磁盘和内存中是一样的
          程序访问存储器所使用的逻辑地址称为虚拟地址,又称为内存偏移地址(memory offset)。与实地址模式下的分段地址类似,虚拟地址也可以写成“段:偏移量”的形式,这个的段是指段选择子。例如“0167:00401000”就是这个表示方法(0167:这个是段选择子,其数据保存在CS段选择器里。同一程序在不同系统环境下,此值可能不同,一般也不需要关心此值)
          基地址:文件执行时将被映射到指定内存地址中,这个初始内存地址称为基地址(imagebase)。这个值是由PE文件本身设定的

    /******************************************************************************

    虚拟地址(virtual memory):相对物理地址来说的概念,不真实存在的

    物理地址(physical address):真实存在的,和物理内存关联的

    页表(page table):管理虚拟内存页和物理内存页映射和缓存状态的数据结构

    页表条目(page table entry PTE):是构成页表的基本元素,是索引号为虚拟页号、值为物理页号的数组

    地址翻译:将虚拟地址映射成物理地址的过程

    页(page):和存储里块一样,类似的单位;虚拟内存中使用页(page)来表示块

    虚拟页(VP):虚拟地址空间划分为多个固定大小的虚拟页

    物理页(PP):物理地址空间划分为多个固定大小的物理页

    页表基地址寄存器(PTBR):CPU有一个专门的页表基地址寄存器,指向当前页表的基地址

    翻译后备缓冲区(TLB):一个用来缓存页表条目PTE的硬件设备

    MMU(Memory Management Unit):CPU中含有的硬件,将虚拟地址转换为物理地址

    重要:

    1、对于CPU来说,它的目标存储器是物理内存,使用cache做物理内存的缓存

    2、对于虚拟内存来说,它的目标存储器是磁盘空间,使用物理内存做磁盘的缓存

    早期内存分配原理

    程序直接运行在物理内存上,操作系统运行多进程时,是如何为这些程序分配内存的?

    例如一台计算机有128M内存,A进程需要10M内存,B进程需要100M内存;操作系统会先将内存中的前 10M 分配给程序 A ,接着再从内存中剩余的 118M 中划分出 110M 分配给程序 B ;如果这时候又运行了需要20M程序 C,系统只剩下 8M 的空间可供使用,此时系统必须在已运行的程序中选择一个将该程序的数据暂时拷贝到硬盘上,释放出部分空间来供程序 C 使用,然后再将程序 C 的数据全部装入内存中运行。

    从早期分配来看,这样有三个问题:

    1、进程的内存地址空间不隔离,有安全隐患

    2、内存效率使用率低;当内存不够时,需要和磁盘进行交互

    3、程序运行地址不确定。我想这个会降低CPU cache命中率

    分段

    解决地址隔离和地址不确定问题,如何实现的?

    所有计算机科学中的问题都能通过增加一个中间转换层来解决,虚拟内存就是中间层的存在;

    程序中访问的内存地址不再是实际的物理内存地址,而是一个虚拟地址;操作系统将这个虚拟地址映射到适当的物理内存地址上;然后把程序全部装入内存;通过映射机制,当程序访问虚拟地址空间上的某个地址值时,就相当于访问了物理地址空间中的另一个值

    当进程创建时,每个进程都会有一个自己的 4GB 虚拟地址空间。要注意的是这个 4GB 的地址空间是“虚拟”的,并不是真实存在的,而且每个进程只能访问自己虚拟地址空间中的数据,无法访问别的进程中的数据,通过这种方法实现了进程间的地址隔离

    分页

    解决内存效率使用问题,如何实现的?

    每个进程都拥有4GB空间,很显然这会超过物理内存空间;而分页的思想是在分段的基础上,程序运行时用到哪页就为哪页分配内存,没用到的页暂时保留在硬盘上。当用到这些页时再在物理地址空间中为这些页分配内存,然后建立虚拟地址空间中的页和刚分配的物理内存页间的映射。

    而虚拟地址和物理地址之间的映射关系是存储在页表中的;页表类似路由表,里面包含一条条虚拟页与物理页的映射关系的条目,页表条目是个数组,索引号对应着虚拟页号,值对应着物理页号和有效位,权限控制位(控制可读,可写,是否需要root权限)

    如图:

    有效位为1的时候表示虚拟页已经缓存。

    有效位为0,数组值为null时,表示未分配的页。

    有效位为0,数组值不为null,表示已经分配了虚拟页,但是还未缓存到具体的物理页中(缺页)

    注意这里的缓存是代表内存中存有数据。

    页表缓存

    页表是被缓存在内存中的,为了防止每次地址翻译操作都需要去访问内存,CPU使用了高速缓存与TLB来缓存PTETLBMMU中的一个缓冲区,其中每一行都保存着一个由单个PTE组成的块

    页表由操作系统管理,并且MMU需要借助存放在内存中的页表来动态翻译虚拟地址

    缺页

    虚拟页没有被缓存在物理内存中(缓存未命中)被称为缺页。

    当CPU遇见缺页时会触发一个缺页异常,缺页异常将控制权转向操作系统内核,然后调用内核中的缺页异常处理程序,该程序会选择一个牺牲页,如果牺牲页已被修改过,内核会先将它复制回硬盘(采用写回机制而不是直写也是为了尽量减少对硬盘的访问次数),然后再把该虚拟页覆盖到牺牲页的位置,并且更新PTE。

    地址翻译

    地址翻译原理:

    n位的虚拟地址划分为p位的虚拟地址偏移量VPO和(n - p)位的虚拟页号VPN;

    MMU根据VPN来选择对应的PTE,例如VPN 0代表PTE 0、VPN 1代表PTE 1….因为物理页与虚拟页的大小是一致的,所以物理页面偏移量(Physical Page Offset, PPO)与VPO是相同的,那么之后只要将PTE中的物理页号(Physical Page Number, PPN)与虚拟地址中的VPO串联起来,就能得到相应的物理地址。

    地址翻译过程:

    1. CPU拿到一个虚拟地址,分为两步,先通过页表机制确定该地址所在虚拟页的内容是否从磁盘加载到物理内存页中,然后通过高速缓存机制从该物理地址中取到数据

    2. 地址翻译硬件要把这个虚拟地址翻译成一个物理地址,从而可以再根据高速缓存的映射关系,把这个物理地址对应的值找到

    3. 地址翻译硬件利用页表数据结构,TLB硬件缓存等技术,目的只是把一个虚拟地址映射到一个物理地址。要记住DRAM缓存是全相联的,所以一个虚拟地址和一个物理地址是动态关联的,不能直接根据虚拟地址推导出物理地址,必须根据DRAM从磁盘把数据缓存到DRAM时存到页表时存的实际物理页才能得到实际的物理地址,用物理页PPN + VPO就能算出实际的物理地址 (VPO = PPO,所以直接用VPO即可)。 PPN的值是存在页表条目PTE中的。地址翻译做了一堆工作,就是为了找到物理页PPN,然后根据VPO页面偏移量,就能定位到实际的物理地址。

    4. 得到实际物理地址后,根据高速缓存的原理,把一个物理地址映射到高速缓存具体的组,行,块中,找到实际存储的数据

    /**************************************************************

    理论上:32位=2^32B = 4 * 2^30B = 4GB,这是 32 位下单进程内存上限

    目前(2015年5月),Intel的32位架构下,可使用的地址线是36个,可使用的最大物理地址是2^36B,折合64GB,可用的地址空间是4GB。

    64位架构下,地址线是46个,所以最大的物理地址是2^46B,折合64TB,可用地址空间也是这么大(目前为止):

    为什么32位Windows中实际可用内存少于4G:

    虽然物理地址有4G,但CPU如果要访问你的显卡上的显存,就必须把物理地址空间的一部分用于标识显存,这种技术被称为memory-mapped I/O,这样可以让CPU操作显存像操作内存一样。

    在Windows的设备管理器里,查看显卡的属性页里的“资源”,可以看到内存映射的地址范围,实际上不管32位还是64位,都需要占用一部分地址空间,32位Windows只有4G的地址空间,被显存占去了一部分,所以可用的地址空间就少于4G了

    实际上不仅仅是显存,你电脑上的PCI控制器,各种网卡、声卡、USB控制器等等都需要占用一定的物理内存,所以最终的后果就是可用的物理地址范围变得特别少,最少可能只有1.99GB,这种限制在32位Windows上是不可改变的。

    所以,32位WIN7的可用内存才变得那么少,解决问题的唯一途径是换64位系统,或者Linux。

    CPUCPU Address Bus Size Maximum RAM 
    808620 bit 1MB
    8088 20 bit 1MB
    80286 24 bit 16MB
    80386SX24 bit 16MB
    80386DX 32 bit 4GB
    80486SX 32 bit 4GB
    80486DX32 bit 4GB
    Pentium I 32 bit 4GB
    K632 bit 4GB
    Duron 32 bit 4GB
    Athlon 32 bit 4GB
    Athlon XP 32 bit4GB
    Celeron  36 bit64GB
    Pentium Pro36 bit 64GB
    Pentium II36 bit64GB
    Pentium III36 bit64GB
    Pentium 4 36 bit64GB
    Athlon  40 bit1TB 
    Athlon-64 40 bit1TB 
    Athlon-64 FX 40 bit1TB 
    Opteron  40 bit1TB 
    Itanium 44 bit 16TB 
    Itanium 2  44 bit16TB 

    PAE确实可以让x86硬件支持到能够访问64G的地址空间,Windows的内核也支持使用多达64G的物理地址空间,但是微软偏偏要对各个版本的Windows的物理内存上限作出限制,下面是XP和Win7的物理内存上限

  • 相关阅读:
    tomcat8.5配置https
    【Linux升级之路】8_Linux多线程
    idea创建父工程统一管理子工程
    vscode配合gitee同步云设置
    Linux零基础入门到进阶
    01. 课程简介
    【PHPWrod】使用PHPWord导出word文档
    多模态模型文本预处理方式
    sql 查重与去重
    BeanUtils.copyProperties使用分析
  • 原文地址:https://blog.csdn.net/u011555996/article/details/127795306