10 如何表示虚拟内存

Posted xuan01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10 如何表示虚拟内存相关的知识,希望对你有一定的参考价值。

x86 CPU 的虚拟地址空间划分:

一个应用往往拥有很大的连续地址空间,并且每个应用都是一样的,只有在运行时才能分配到真正的 物理内存,在操作系统中被称为虚拟内存;

x86CPU支持虚拟地址时要么开启保护模式要么开启长模式;保护模式下是32位,没有进行任何划分;长模式下64位,但是CPU只是实现了48位的地址空间,寄存器确实64位的,CPU用地址数据的47位扩展到最高16位,因此,要么全0、要么全1;

Cosmos 划分虚拟地址:

 由以上长模式可以看出,0xFFFF800000000000~0xFFFFFFFFFFFFFFFF分给内核;0 ~ 0x00007FFFFFFFFFFF分给应用;

进一步做细分: 应用空间的最顶端是应用程序的栈,线下增长;堆是在应用程序数据区的后面,向上增长;低地址存放应用指令区和数据区;

在内核的低地址区0xFFFF800000000000~0xFFFF800400000000存放线性映射区;这是在二级引导区中建立的MMU页表映射;

设计数据结构:

虚拟地址区间、管理虚拟地址区间、对应的物理页面等;

  虚拟地址区间:

虚拟地址空间往往是以区间为单位的,比如栈区、堆区、指令区、数据区;;区内部连续,区与区至之间间隔很大;当涉及到区空间的扩大时,不用建立新的虚拟地址区间数据结构,只是改变其中的指针;

kmvarsdsc_t 结构体:包含虚拟地址的开始与结束字段、自旋锁、链表、类型等;

  整个虚拟地址空间:

多个虚拟地址区间连接成整个虚拟地址空间;

virmemadrs_t 结构管理了整个虚拟地址空间的区间 kmvarsdsc_t 结构体;

  进程的内存地址空间:

虚拟地址空间作作用于应用程序,而应用程序在操作系统中用进程表示;一个进程由虚拟地址空间信息、进程和虚拟地址和物理地址的映射信息、应用程序文件中的指令区、数据区的开始、结束地址信息;

mmadrsdsc_t 结构体表示这些信息, 包含了mmudsc_t 表示的MMU的页表数据;

  页面盒子:

每段虚拟地址区间,都会映射到对应的物理页面,根据物理内存管理器的设计,分配完页面后,会返回一个msadsc_t 结构体,所以还需要一个数据结构来挂载msadsc_t 结构体;

不把它挂载到虚拟地址区间的结构体中,出于:把一个文件映射到进程的虚拟地址空间中,只需要在内存页面保留一份共享文件,多个程序就可以共它,常规操作就是把同一物理内存页面映射到不同的虚拟地址区间,因此我们实现了一个专用的数据结构,共享操作就可以让多个 kmvarsdsc_t 结构指向它;

kvmemcbox_t 结构体实现了上述功能;可以独立存在,又和虚拟内存区间有紧密的联系,甚至可以用来管理文件数据占用的物理内存页面;

  页面盒子的头:

kvmemcboxmgr_t 结构体 用来管理所有的 kvmemcbox_t 结构;

作为全局数据结构,用于找到 并 对kvmcbox_t 结构体计数;还要支持缓存多个空闲的kvmemcbox_t 结构体;

缓存是为了放置频繁分配、释放kvmemcbox_t 结构带来的系统性能抖动;同时,可以供下次取出即用,不必再找内核申请,大大提高性能;

  数据结构之间的关系:

首先从进程的虚拟地址空间开始,进程的虚拟地址是 kmvarsdsc_t 结构表示,一个kmvarsdsc_t 结构表示 一个已经分配出去的虚拟地址空间;一个进程所有的 kmvarsdsc_t 结构,要交给进程的mmadrsdsc_t 结构中的 virmemadrs_t 结构管理;

为了管理虚拟地址空间对应的物理内存页面,建立了kvmembox_t 结构,由kvmemcboxmgr_t 结构统一管理,在kvmembox_t 结构中,挂载了物理内存页面对应的 msadsc_t 结构;

初始化:

虚拟地址空间的分配与释放,依赖于进程数据结构下的 mmadrsdsc_t  结构,实例一个结构变量,进行初始化;

这个在属于内核层功能;init_kvirmemadrs 函数首先调用了mmadrsdsc_t_init 函数,初始化 mmadrsdsc_t 结构;接着调用了 kvma_inituserspace_virmemadrs 函数,这个函数中建立了一个虚拟地址区间和 一个栈区间;栈区位于虚拟地址空间的顶端;

在init_krl 函数中调用init_krlmm 函数,此函数调用我们的 init_kvirmemadrs 函数;

 

操作系统 虚拟内存技术

前言

本文介绍操作系统里的虚拟内存技术,它是目前最常用的内存扩充技术。

本文先介绍了虚拟内存的概念,
再介绍如何实现虚拟内存,只以请求分页管理方式为例来表示如何实现;
再比较各种页面置换算法,用以确定将哪个页面换出到外存;
最后是操作系统如何给进程页面分配、置换的策略;
从以上几个方面来理解虚拟内存技术。

虚拟内存技术的概念

传统存储管理方式的特征、缺点

  • 特征1,一次性:作业必须一次性全部装入内存后才能开始运行。
    这会造成以下两个问题:

    1. 作业很大时,不能全部装入内存,导致大作业无法运行;
    2. 当大量作业要求运行时,由于内存无法容纳所有作业,因此只有少量作业能运行,导致多道程序并发度下降。
  • 特征2,驻留性:一旦作业被装入内存,就会一直驻留在内存中,直至作业运行结束;
    由于局部性原理,将会导致了内存中会驻留大量的、暂时用不到的数据,浪费了宝贵的内存资源。

这些问题都将通过虚拟内存技术解决。

局部性原理

局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。

  • 时间局部性
    如果执行了程序中的某条指令,那么不久之后这条指令很有可能再次执行;
    如果某个数据被访问过,不久之后该数据很可能再次被访问(因为程序中存在大量的循环);

  • 空间局部性
    如果程序访问了某个存储单元,那么不久之后其附近的内存单元也很有可能被访问(因为很多程序在内存中都是连续存放的)。

  • 高速缓存技术就是局部性原理的应用;
    将近期会频繁访问到的数据放到更高速的存储器中,暂时用不到的数据放在更低速存储器中。
    快表机制就是高速缓冲技术思想的典型应用;

虚拟内存的定义和特征

基于局部性原理,就可以在程序装入时,可以将程序中很快会用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行;
在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外面调入内存,然后继续执行程序;
若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存;

在操作系统的管理下,在用户看来似乎有一个比实际内存大的多的内存,这就是虚拟内存。

  • 虚拟内存的容量:

    1. 虚拟内存的最大容量:
      由CPU寻址范围确定的,32位即4G可用内存;

    2. 虚拟内存的实际容量:
      由 min(CPU寻址范围,内存和外存容量之和)决定;

  • 虚拟内存的特征:

    1. 多次性:
      无需在作业运行时一次性全部装入内存,而是运行被分成多次调入内存;
    2. 对换性:
      在作业运行时无需一直常驻内存,而是允许在作业运行过程中,将作业换入、换出;
    3. 虚拟性:
      从逻辑上扩充了内存的容量,使用户看到的内存容量,远远大于实际的容量。

如何实现虚拟内存技术

与传统的非连续分配存储管理方式上的主要区别是添加请求调页功能和页面置换功能;

  • 请求调页功能:
    在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外面调入内存,将缺失页面从外存调入内存,然后继续执行程序;

  • 页面置换功能:
    若内存空间不够,由操作系统负责将内存中暂时用不到的页面换出到外存;

请求分页存储管理

操作系统 内存管理 分页/分段/段页式管理

页表机制

请求分页管理中,为了实现请求调页,操作系统需要知道每个页面是否已经调入内存;如果没有调入,也么也需要知道该页面在外存中存放的位置;
当内存空间不够时,要实现页面置换,操作系统也需要通过某些指标来决定到底换出哪个页面;有的页面没有被修改过,就不用再浪费时间写回外存;有的页面修改过,就需要将外存中的旧数据覆盖,因此操作系统也需要记录各个页面是否被修改的信息。

缺页中断机构

  • 在请求分页系统中,每当要访问的页面不在内存时,便产生一个缺页中断,然后由操作系统的缺页中断处理程序处理中断。此时缺页的进程阻塞,放入阻塞队列,调页完成后再将其唤醒,放回就绪队列。

  • 如果内存中有空闲块,则为进程分配一个空闲块,将所缺页面装入该块,并修改页表中相应的页表项;
    如果内存中没有空闲块,则由页面置换算法选择一个页面淘汰,若该页面在内存期间被修改过,则要将其写回外存,未修改过的页面不用写回外存。

  • 缺页中断是因为当前执行的指令想要访问的目标页面未调入内存而产生的,因此属于内中断。

  • 一条指令在执行期间,可能产生多次缺页中断。

地址变换机构

  • 在具有快表机构的请求分页系统中,访问一个逻辑地址时,若发生缺页,则地址变换步骤是:
    查快表(未命中)
    –> 查慢表(发现未被调入内存)
    –> 调页(调入的页面对应的表项会直接加入快表中)
    –> 查快表(命中)
    –> 访问目标内存单元

  • 注意:

    1. 只有写指令才需要修改修改位。
      并且一般来说只需要修改快表中的数据,只有要将快表项删除时才需要写回内存中的慢表,这样可以减少内存访问次数。
    2. 和普通的中断处理一样,缺页中断处理依然需要保留CPU现场;
    3. 需要用某种页面置换算法,来决定一个换出页面
    4. 换入/换出页面都需要启动慢速IO操作,可见,如果换出/换出太频繁,会有很大的开销;
    5. 页面调入内存后,需要修改慢表,同时也需要将表项复制到快表中。
  • 地址变换流程图

页面置换算法

在请求分页存储管理中,当内存空间不够时,需要使用页面置换算法来决定将哪个页换出到外存。因为页面的换入/换出是IO操作,会有较大的开销,因此好的页面置换算法应该追求更少的缺页率

最佳置换算法OPT

  • 算法思想:
    每次选择淘汰的页面将是以后永不使用、或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。

  • 优缺点:
    最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面,操作系统无法提前预判页面访问序列,因此最佳置换算法是无法实现的。

先进先出置换算法 FIFO

  • 算法思想:
    每次选择淘汰的页面是最早进入内存的页面。

  • 会产生Belady异常:
    当为进程分配的物理块数增大时,缺页次数不减反增的异常现象;

  • 优缺点:
    FIFO算法实现虽然简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问,因此算法性能差。

最近最久未使用置换算法 LRU

  • 算法思想:
    每次淘汰的页面是最近最久未使用的页面;

  • 优缺点:
    该算法的实现需要专门的硬件支持,算法性能好,是最接近OPT算法的,但是实现困难,开销大;

时钟置换算法 CLOCK,NRU

时钟置换算法是一种性能和开销比较均衡的算法,又称为CLOCK算法,或最近未使用算法(NRU,Not Recently Used)

  • 简单的算法思想:
    为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个环形队列。
    当页面被访问时,其访问位为1;
    当需要淘汰一个页面时,只需检查页的访问位;如果是0,就将该页换出;如果是1,则将他置为0,暂不换出,继续向下检查直到找到为0的;
    若所有页面都是1,则会在第一轮扫描后全部被置为0;第二轮扫描时就会将首位换出。
    因此简单的CLOCK算法选择一个淘汰页面最多会经历两轮扫描;

  • 优缺点:
    实现简单,算法开销小,但未考虑到页面是否被修改过;

改进型时钟置换算法

  • 改进型的时钟置换算法思想:
    简单的时钟置换算法只考虑到一个页面最近是否被访问过,但事实上,如果被淘汰的页面没有被修改过,就不需要执行IO操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。
    所以,应该优先淘汰没有被修改过的页面,避免IO操作;
    在表项中添加修改位,为0表示没有被修改过,为1表示修改过。

  • 算法规则如下所示:

  • 优缺点:
    算法开销较小,性能也不错。

页面分配策略

驻留集

驻留集是指请求分页存储管理中给进程分配的物理块的集合;
在采用了虚拟存储技术的操作系统中,驻留集大小一般小于进程的总大小;
若驻留集太小,会导致频繁缺页,性能消耗大;若驻留集太大,会导致多道程序并发度下降,资源利用率低;所以应该选择一个合适的驻留集大小。

页面分配、置换策略

  • 页面分配:

    1. 固定分配:
      操作系统为每个进程分配一组固定数目的物理块,在进程运行期间不再改变,即驻留集大小不变;
    2. 可变分配:
      先为每个进程分配一定数据的物理块,在进程运行期间,可根据情况做适当的增加或减少,即驻留集可变;
  • 置换策略:

    1. 局部置换:
      发生缺页时只能选择进程自己的物理块进行置换
    2. 全局置换:
      可以将操作系统保留的空闲物理块分配给缺页进程,也可以将别的进程持有的物理块置换到外存,再分配给缺页进程;
  • 可变分配全局置换和可变分配局部置换区别
    可变分配全局置换:只要缺页就给分配新物理块
    可变分配局部置换:要根据发生缺页的频率来动态的增加或减少进程的物理块

固定分配局部置换

系统为每个进程分配一定梳理的物理块,在整个运行期间都不改变;
若进程在运行中发生缺页,则只能从该进程在内存中的页面中选出一页换出,然后再调入需要的页面;
这种策略的缺点是:很难在刚开始就确定应为每个进程分配多少个物理块才算合理。

可变分配全局置换

刚开始会为每个进程分配一定数量的物理块,操作系统会保持一个空闲物理块队列;
当某进行发送缺页时,从空闲物理块中取出一块分配给该进程;若已无空闲物理块,则可选择一个未锁定的页面换出外存,再将该物理块分配给缺页的进程。
采用这种策略时,只要某进程发生缺页,都将获得新的物理块,仅当空闲物理块用完时,系统才会选择一个未锁定的页面调出,被选择调出的页可能是系统中任何一个进程的页,因此该被选中的进程物理块会减少,缺页率增加。

可变分配局部置换

刚开始为每个进程分配一定数量的物理块,当某进程发生缺页时,只允许从该进程自己的物理块中选出一个进行换出外存;
如果进程在运行中频繁缺页,系统会为该进程多分配几个物理块,直至该进程缺页率趋势到适当程度;反之,如果进程在运行中缺页率极低,则可适当的减少分配给该进程的物理块;

何时调入页面

  1. 预调页策略
    一般用于进程运行前,由程序员指出应该先调入哪些部分;

  2. 请求调页策略
    进程运行时,发生缺页再调页。

从何处调入页面

  • 对换区足够大:
    在进程运行前,将数据从文件区复制到对换区,之后所有的页面调入、调出都是在内存与对换区之间进行;

  • 对换区不够大:
    不会修改的数据每次都从文件区调入,会修改的数据调出到对换区,需要时再从对换区调入;

  • UNIX方式:
    第一次使用时的页面全部都文件区调入;调出的页面都写回对换区,再次使用时从对换区调入;

抖动(颠簸)现象

是指刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出外存,这种频繁的页面调度行为成为抖动,或颠簸。
产生抖动的主要原因是进程频繁访问的页面数目高于可用的物理块数。

  • 工作集:
    指在某段时间内,进程实际访问页面的集合;

  • 操作系统为根据窗口尺寸来算出工作集;
    实际应用中,操作系统可以统计出进程的工作集大小,根据工作集大小给进程分配若干内存块。

  • 一般来说,驻留集大小不能小于工作集大小,否则进程运行过程中将会频繁缺页,可能导致抖动现象。

以上是关于10 如何表示虚拟内存的主要内容,如果未能解决你的问题,请参考以下文章

Android上如何查看CPU和内存信息

云帮手在windows下提示虚拟内存不足,如何解决?

centos 设置虚拟内存SWAP

操作系统 虚拟内存技术

如何查看虚拟内存使用情况

Linux学习笔记第七周一次课(3月19日)