物理地址、虚拟地址、虚拟内存、分段、分页以及Windows/Linux内存管理

时间:2024-04-12 15:14:44

每日三问/操作系统篇<1>:物理地址、虚拟地址、虚拟内存是什么?

  • 物理地址:内存芯片级的单元寻址,是放在寻址总线上的地址,加载到内存地址寄存器中的地址,内存单元的真正地址。物理地址是明确的、最终用在总线上的编号,不必转换,不必分页,也没有特权级检查。

  • 虚拟地址:没有经过分页机制和分段机制转换的地址,也就是段寄存器和变址寄存器内容的组合。

    • 逻辑地址:上层程序员可以操作的地址,和段相关的偏移地址部分,也就是变址寄存器中存储的32位偏移地址,而其他寄存器上的地址往往对于上层程序员来说是不可更改甚至是不可见的. 只有在实模式下,逻辑地址才和物理地址一致(因为实模式没有分段或分页机制,Cpu不进行自动地址转换);逻辑地址也就是在保护模式下程序执行代码段限长内的偏移地址(假定代码段、数据段如果完全一样).应用程序员仅需与逻辑地址打交道,而分段和分页机制对您来说是完全透明的,仅由系统编程人员涉及.应用程序员虽然自己可以直接操作内存,那也只能在操作系统给你分配的内存段操作。
    • 线性地址:逻辑地址到物理地址变换之间的中间层。虚拟地址通过分段机制以后,可以得到段基址、段界限以及段偏移地址(即逻辑地址),段基址与段偏移地址的组合就是线性地址。

    虚拟内存空间图:

物理地址、虚拟地址、虚拟内存、分段、分页以及Windows/Linux内存管理

  • 虚拟内存:操作系统的一项技术,当程序被载入内存时,运用虚拟内存技术可以让程序误以为自己正在独占电脑可用内存,能够占用电脑所有的内存,以及访问所有内存地址。虚拟内存通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。虚拟内存能够防止操作系统内存消耗殆尽。虚拟内存是一种逻辑上扩充物理内存的技术。基本思想是用软、硬件技术把内存与外存这两级存储器当做一级存储器来用。虚拟内存技术的实现利用了自动覆盖和交换技术。简单的说就是将硬盘的一部分作为内存来使用。

虚拟地址到物理地址的变换过程图:

物理地址、虚拟地址、虚拟内存、分段、分页以及Windows/Linux内存管理

线性地址和物理地址之间的变换过程图:

物理地址、虚拟地址、虚拟内存、分段、分页以及Windows/Linux内存管理

每日三问/操作系统篇<2>: 什么是分段、分页,有什么区别?

  • 分段存储管理:将程序地址空间分成若干段,段大小不定,每段定义一组相对完整信息,在内存分配时以段为单位,分段的使用为了满足用户的编程和使用要求。

    • 分段机制:分段机制就是把虚拟地址空间中的虚拟内存组织成一些长度可变的称为段的内存块单元。
      物理地址、虚拟地址、虚拟内存、分段、分页以及Windows/Linux内存管理
    用户通常将自己的程序按逻辑分成若干段,每段从0开始编址,有名称和长度,如:程序段text,数据段data,栈等,同理段存储很好解决了数据段动态增长,程序的动态链接等问题。
  • 分页存储管理:将用户程序的地址空间分成若干个固定大小区域,称为页,同时将内存空间分成对应大小物理块。系统中维护一个页表,通过页与物理块的对应,完成逻辑地址到物理地址(实际内存的地址,比如内存条)的映射。

    • 分页机制: 分页机制在段机制之后进行的,它进一步将线性地址转换为物理地址。

物理地址、虚拟地址、虚拟内存、分段、分页以及Windows/Linux内存管理

物理地址、虚拟地址、虚拟内存、分段、分页以及Windows/Linux内存管理

当进程访问某个逻辑地址中数据,分页系统地址变换机构,用页号检索页表,如果页号大于或等于页表长度,则产生地址越界中断。否则将页表初始地址与页号和页表项长度乘积相加得到页表物理号的地址,获取到物理块号。再将物理块得到的地址与页内地址组合得到物理地址。如果选择的页面太小,虽然可以提高内存利用率,但是每个进程使用过多页面,导致页表过长。降低页面换入换出效率。

分段与分页的区别:

1.页是信息的物理单位,分页是为了实现离散分配方式,以消减内存的外零头,提高内存的利用率。分页仅仅是由于系统管理的需要而不是用户的需要,段是信息的逻辑单位,分段的目的是为了能更好地满足用户的需要。
2.页的大小固定,由系统把逻辑地址划分为页号和页内地址两部分,段的长度却不固定,决定于用户所编写的程序。
3.分页的作业地址空间是一维的,即单一的线性地址空间。 分段的作业地址空间是二维的 在标识一个地址时,即需给出段名,又需给出段内地址。

每日三问/操作系统篇<3>: 讲讲Windows/Linux内存管理?

Windows

Windows的内存体系结构基于虚拟的线性的地址和分页机制。对于线性地址的分配也是以页为单位进行的,物理地址的管理更是以页为单位。

当我们在Windows中双击一个应用程序图标后,系统为该应用程序创建一个进程,Windows使得每个进程都拥有2GB的地址空间,这2GB地址空间用于程序存放代码,数据,堆栈,*存储区(堆),另外2GB用于共享系统使用前面的这些地址并不是物理内存中的地址。

Windows是多任务的系统,在每个进程创建时,系统为每个进程也创建了一个页表,用于虚拟地址到物理地址的转换。比如现在程序在执行进程A,用户切换到了另外一个进程B,则系统会将进程A在内存中的数据存放到页文件中,并更新进程A的页表(使虚拟地址和页文件形成映射)。然后读取进程B的页表,根据页表判断进程B的数据是在内存中还是在页文件中(通过页文件的类型来判断),如果在内存中就直接读取,如果在页面文件中,就将页面文件内容读入物理内存,然后更新页表(使虚拟地址和物理内存形成映射)。

Linux

Linux的内存管理采取的是分页存取机制,为了保证物理内存能得到充分的利用,内核会在适当的时候将物理内存中不经常使用的数据块自动交换到虚拟内存中,而将经常使用的信息保留到物理内存。

Linux系统会不时的进行页面交换操作,以保持尽可能多的空闲物理内存,即使并没有什么事情需要内存,Linux也会交换出暂时不用的内存页面。这可以避免等待交换所需的时间。

Linux进行页面交换是有条件的,不是所有页面在不用时都交换到虚拟内存,Linux内核根据”最近最经常使用“算法,仅仅将一些不经常使用的页面文件交换到虚拟内存,有时我们会看到这么一个现象:Linux物理内存还有很多,但是交换空间也使用了很多。其实,这并不奇怪,例如,一个占用很大内存的进程运行时,需要耗费很多内存资源,此时就会有一些不常用页面文件被交换到虚拟内存中,但后来这个占用很多内存资源的进程结束并释放了很多内存时,刚才被交换出去的页面文件并不会自动的交换进物理内存,除非有这个必要,那么此刻系统物理内存就会空闲很多,同时交换空间也在被使用,就出现了刚才所说的现象了。关于这点,不用担心什么,只要知道是怎么一回事就可以了。
最后,交换空间的页面在使用时会首先被交换到物理内存,如果此时没有足够的物理内存来容纳这些页面,它们又会被马上交换出去,如此以来,虚拟内存中可能没有足够空间来存储这些交换页面,最终会导致Linux出现假死机、服务异常等问题,Linux虽然可以在一段时间内自行恢复,但是恢复后的系统已经基本不可用了。