前言

虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。

覆盖和技术

  • 覆盖

依据程序逻辑结构,将程序划分为若干功能相对独立的模块;将不会同时执行的模块共享同一块内存区域

但是由于需要程序员来划分功能模块和确定模块之间的覆盖关系,所以增加了编程难度,并且也增加了执行时间

  • 交换

交换技术和覆盖技术讨论的不一样的是,交换技术讨论的是当前内存足够当前的单个程序运行的内存,但是对于多道程序可能会有运行内存不够的情况

实现方法可以将暂时不能运行的程序放到外存当中,再运行时来执行换入换出操作

程序在执行过程中的一个较短时期,所执行的指令地址和指令的操作数地址,分别局限于一定区域 -->

虚拟内存

在装载程序时,只将当前指令执行需要的部分页面或段装入内存,指令执行中需要的指令或数据不在内存(称为缺页)时,处理器通知操作系统将相应的页面调入内存,操作系统将内存中暂时不同的页面保存到外存

虚拟内存在页机制的基础上,也就是增加了请求调页和页面置换

  • 当用户程序要装载到内存运行时,只装入部分页面,就启动程序运行
  • 进程在运行中发现有需要的代码或数据不在内存时,则向系统发出缺页异常请求
  • 操作系统在处理缺页异常时,将外存中相应的页面调入内存,使得进程能继续运行

页表项结构

  • 驻留位:表示该页是否在内存
  • 修改位:表示在内存中的该页是否被修改过
  • 访问位:表示该页面是否被访问过(读或写)
  • 保护位:表示该页的允许访问方式

缺页中断处理

  1. 在内存中有空闲物理页面时,分配一物理页帧f,转第5步;
  2. 依据页面置换算法选择将被替换的物理页帧f,对应逻辑页q
  3. 如q被修改过,则把它写回外存;
  4. 修改q的页表项中驻留位置为0;
  5. 将需要访问的页p装入到物理页面f
  6. 修改p的页表项驻留位为1,物理页帧号为f;
  7. 重新执行产生缺页的指令

页面置换

刚刚在上面说到当发生缺页中断的时候,可能当前已经没有了空闲的物理页了,那就需要进行页面置换

局部页面置换算法

置换的页面仅限于当前进程占用的物理页面内

  • 先进先出算法

    维护一个记录所有位于内存中的逻辑页面链表,链表元素按驻留内存的时间排序,链首最长,链尾最短,出现缺页时,选择链首页面进行置换,新页面加到链尾

  • 最近最久未使用算法

    缺页时,计算内存中每个逻辑页面的上一次访问时间,选择上一次使用到当前时间最长的页面

    最近最久未使用算法实现一般有两种方法:

    1. 页面链表

      系统维护一个按最近一次访问时间排序的页面链表,访问内存时,找到相应页面,并把它移到链表之首,缺页时,置换链表尾节点的页面
    2. 活动页面栈

      访问页面时,将此页号压入栈顶,并栈内相同的页号抽出,缺页时,置换栈底的页面
  • 时钟置换算法

    在页表项中增加访问位,描述页面在过去一段时间的内访问情况,各页面组织成环形链表,指针指向最先调入的页面,访问页面时,在页表项记录页面访问情况,缺页时,从指针处开始顺序查找未被访问的页面进行置换

  • 最不常用算法

    缺页时,置换访问次数最少的页面,访问页面时,访问计数加1

全局页面置换算法

置换的页面包括所有可用的物理页面内

  • 工作集置换算法

    当前时刻前τ个内存访问的页引用是工作集,τ被称为窗口大小,访存链表:维护窗口内的访存页面链表,访存时,换出不在工作集的页面;更新访存链表,缺页时,换入页面;更新访存链表

  • 缺页率置换算法

    访存时,设置引用位标志,缺页时,计算从上次缺页时间tlast 到现在tcurrent 的时间间隔,如果 tcurrent – tlast>T, 则置换所有在[tlast , tcurrent ]时间内没有被引用的页,如果tcurrent – tlast ≤ T, 则增加缺失页到工作集中

缺页中断代码实现

当启动分页机制以后,如果一条指令或数据的虚拟地址所对应的物理页框不在内存中或者访问的类型有错误(比如写一个只读页或用户态程序访问内核态的数据等),就会发生页访问异常

和之前说的普通的中断一样,由CPU发送一个中断信号,然后到最后是由trap_dispatch进行分发处理

case T_PGFLT:  //page fault
if ((ret = pgfault_handler(tf)) != 0) {
print_trapframze(tf);
panic("handle pgfault failed. %e\n", ret);
}
break;

其中最重要的就是处理缺页异常的函数

int
do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr) {
int ret = -E_INVAL;
struct vma_struct *vma = find_vma(mm, addr); pgfault_num++;
if (vma == NULL || vma->vm_start > addr) {
cprintf("not valid addr %x, and can not find it in vma\n", addr);
goto failed;
}
//check the error_code
switch (error_code & 3) {
default:
/* error code flag : default is 3 ( W/R=1, P=1): write, present */
case 2: /* error code flag : (W/R=1, P=0): write, not present */
if (!(vma->vm_flags & VM_WRITE)) {
cprintf("do_pgfault failed: error code flag = write AND not present, but the addr's vma cannot write\n");
goto failed;
}
break;
case 1: /* error code flag : (W/R=0, P=1): read, present */
cprintf("do_pgfault failed: error code flag = read AND present\n");
goto failed;
case 0: /* error code flag : (W/R=0, P=0): read, not present */
if (!(vma->vm_flags & (VM_READ | VM_EXEC))) {
cprintf("do_pgfault failed: error code flag = read AND not present, but the addr's vma cannot read or exec\n");
goto failed;
}
} uint32_t perm = PTE_U;
if (vma->vm_flags & VM_WRITE) {
perm |= PTE_W;
}
addr = ROUNDDOWN(addr, PGSIZE); ret = -E_NO_MEM; pte_t *ptep=NULL; if ((ptep = get_pte(mm->pgdir, addr, 1)) == NULL) {
cprintf("get_pte in do_pgfault failed\n");
goto failed;
} if (*ptep == 0) { // if the phy addr isn't exist, then alloc a page & map the phy addr with logical addr
if (pgdir_alloc_page(mm->pgdir, addr, perm) == NULL) {
cprintf("pgdir_alloc_page in do_pgfault failed\n");
goto failed;
}
}
else { // if this pte is a swap entry, then load data from disk to a page with phy addr
// and call page_insert to map the phy addr with logical addr
if(swap_init_ok) {
struct Page *page=NULL;
if ((ret = swap_in(mm, addr, &page)) != 0) {
cprintf("swap_in in do_pgfault failed\n");
goto failed;
}
page_insert(mm->pgdir, page, addr, perm);
swap_map_swappable(mm, addr, page, 1);
page->pra_vaddr = addr;
}
else {
cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
goto failed;
}
}
ret = 0;
failed:
return ret;
}
  • 首先查找此地址是否在某个VMA的地址范围内和根据errorcode看是否满足正确的读写权限
  • 如果在此范围内并且权限也正确,这认为这是一次合法访问,但没有建立虚实对应关系
  • 如果都不是就是需要进行页的换入操作

页面置换机制代码实现

页面置换这里采用了最简单的FIFO算法

其中最重要的两个函数是_fifo_map_swappable和_fifo_swap_out_victim

static int _fifo_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in) {
list_entry_t *head=(list_entry_t*) mm->sm_priv;
list_entry_t *entry=&(page->pra_page_link);
assert(entry != NULL && head != NULL);
list_add(head, entry); //将最近用到的页面添加到次序队尾
return 0;
}

它的主要作用是将最近被用到的页面添加到算法所维护的次序队列

static int
_fifo_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page, int in_tick) {
list_entry_t *head=(list_entry_t*) mm->sm_priv;
assert(head != NULL);
assert(in_tick==0);
list_entry_t *le = head->prev; //用le指示需要被换出的页
assert(head!=le);
struct Page *p = le2page(le, pra_page_link);//le2page宏可以根据链表元素获得对应的Page指针p
list_del(le); //将进来最早的页面从队列中删除
assert(p !=NULL);
*ptr_page = p; //将这一页的地址存储在ptr_page中
return 0;
}

_fifo_swap_out_victim()函数是用来查询哪个页面需要被换出,它的主要作用是用来查询哪个页面需要被换出

Lab3:虚拟内存管理的更多相关文章

  1. ucore操作系统学习(三) ucore lab3虚拟内存管理分析

    1. ucore lab3介绍 虚拟内存介绍 在目前的硬件体系结构中,程序要想在计算机中运行,必须先加载至物理主存中.在支持多道程序运行的系统上,我们想要让包括操作系统内核在内的各种程序能并发的执行, ...

  2. ucore lab3 虚拟内存管理 学习笔记

    做个总结,这节说是讲虚拟内存管理,大部分的时间都在搞SWAP机制和服务于此机制的一些个算法.难度又降了一截. 不过现在我的电脑都16G内存了,能用完一半的情景都极少见了,可能到用到退休都不见得用的上S ...

  3. 十问 Linux 虚拟内存管理 (glibc) (二)

    版权声明:本文由陈福荣原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/184 来源:腾云阁 https://www.qclo ...

  4. SoC嵌入式软件架构设计II:没有MMU的CPU虚拟内存管理的设计和实现方法

    大多数的程序代码是必要的时,它可以被加载到内存中运行.手术后,可直接丢弃或覆盖其它代码. 我们PC然在同一时间大量的应用,地址空间差点儿能够整个线性地址空间(除了部分留给操作系统或者预留它用).能够觉 ...

  5. SoC嵌入式软件架构设计II:否MMU的CPU虚拟内存管理的设计与实现方法

    大多数的程序代码是必要的时,它可以被加载到内存中运行.手术后,可直接丢弃或覆盖其他代码.我们PC然在同一时间大量的应用,能够整个线性地址空间(除了部分留给操作系统或者预留它用),能够觉得每一个应用程序 ...

  6. windows虚拟内存管理

    内存管理是操作系统非常重要的部分,处理器每一次的升级都会给内存管理方式带来巨大的变化,向早期的8086cpu的分段式管理,到后来的80x86 系列的32位cpu推出的保护模式和段页式管理.在应用程序中 ...

  7. OS之内存管理 --- 虚拟内存管理(二)

    关于虚拟内存管理之前的请看:OS之内存管理 - 虚拟内存管理(一) 帧分配 每个进程对的最小帧数是由操作系统的体系结构决定的,但是最大帧数是由可用物理内存的数量决定的.所以在这之间,对于进程的帧的分配 ...

  8. linux内核内存分配(三、虚拟内存管理)

    在分析虚拟内存管理前要先看下linux内核内存的具体分配我開始就是困在这个地方.对内核内存的分类不是非常清晰.我摘录当中的一段: 内核内存地址 ============================ ...

  9. Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载

    Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...

  10. Unix系统编程()虚拟内存管理

    在之前学到过进程的内存布局中忽略了一个事实:这一布局存在于虚拟文件中. 因为对虚拟内存的理解将有助于后续对fork系统调用.共享内存和映射文件之类的主题阐述,这里还要学习一下有关虚拟内存的详细内容. ...

随机推荐

  1. JS提交表单页面不跳转、JS下载、动态创建from

    JS下载 function downloadFile(id) {     var url =  "<%=request.getContextPath()%>/cer/downlo ...

  2. jdk8 接口的变化

    在jdk8之前,interface之中可以定义变量和方法,变量必须是public.static.final的,方法必须是public.abstract的.由于这些修饰符都是默认的以下写法等价 publ ...

  3. 小程序上传图片功能 uploadFile:fail Read error:ssl=0xa738d808:I/O error during system call,Connection reset by peer

    由于纯网页上传图片小程序会闪退,就采用了小程序原生的上传功能wx.uploadfile 处理流程: 1.网页需要跳转到小程序 需要引用 <script src='https://res.wx.q ...

  4. RFID相关知识总结(超高频UHF)

    RFID标签分类 1.LF(Low frequency) 低频 频段范围: 125 KHz-135KHz(ISO18000-2) 常见应用:该频段特点是具有良好的物体穿透能力.广泛应用于进出管理.门禁 ...

  5. python——CSV转Excel

    在转换之前,事先需要将csv文件另存为此格式 import pandas as pd def csv_to_xlsx_pd(): csv = pd.read_csv(r'C:\Users\Jery\D ...

  6. mask-rcnn解读(二):clip_boxes_graph()

    此函数是利用deltas对box修正,我并没有详细说明,若有问题,欢迎留言交流: def clip_boxes_graph(boxes, window): """ box ...

  7. Struts2处理(jQuery)Ajax请求

    1. Ajax     Ajax(Asynchronous JavaScript and XML,异步JavaScript和XML)时一种创建交互式网页应用的网页开发技术,它并不是一项新的技术,其产生 ...

  8. vi/vim的快捷操作(2)

    1.拷贝当前行[yy],拷贝当前行向下的5行[5yy],并粘贴[p] 2.删除当前行[dd],删除当前行向下的5行[5dd] 3.在文件中查找某个单词,命令行模式下输入[/关键字],回车查找,输入[n ...

  9. python实现生产者消费者模型

    生产者消费之模型就是,比如一个包子铺,中的顾客吃包子,和厨师做包子,不可能是将包子一块做出来,在给顾客吃,但是单线程只能这麽做,所以用多线程来执行,厨师一边做包子,顾客一边吃包子,当顾客少时,厨师做的 ...

  10. matplotlib 自带的几种美化样式

    1.用 matplotlib.pyplot.style.avaliable 可查看 matplotlib 自带的美化样式如下: ['bmh', 'classic', 'dark_background' ...