前言

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

覆盖和技术

  • 覆盖

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

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

  • 交换

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

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

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

虚拟内存

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

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

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

页表项结构

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

缺页中断处理

  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. python输入一个字符串,输出翻转后的字符串(翻转字符串)

    题目:输出一个字符串,输出翻转后的字符串.例如:输入字符串a123,输出321a. 方法一:使用列表的reverse方法 string=input('请输入一个字符串:') lst=list(stri ...

  2. 10、VUE路由技术

    1.前端路由 前端路由在很多开源的js类库框架中都得到支持,如AngularJS.Backbone.Vue.js等等. 前端路由和后端路由原理一样,是让所有的交互和展示在一个页面运行,以达到减少服务器 ...

  3. 阿里云Centos7用putty ssh链接掉线

    解决方法:修改云服务器 ssh 配置文件(修改前一定要先备份) (1)打开配置文件: vim /etc/ssh/sshd_config 1 (2)找到下面两行: ClientAliveInterval ...

  4. 线程安全---Day23

    最近忙着备考大学四年最后的两科,昨天刚考完大学所有的考试,但是大学专业是机械,但是自己热衷于IT行业,想往IT行业走,希望毕业后能成功进入到IT行业,只希望毕业能找到一份Java开发工程师的工作,这样 ...

  5. 2019-09-16 curl简单操作

    1.get请求 (使用file_get_contents()函数也可以实现get请求) //http_build_query() 构造一个url字符串 function http_get($url) ...

  6. spring data jpa使用详解

    https://blog.csdn.net/liuchuanhong1/article/details/52042477 使用Spring data JPA开发已经有一段时间了,这期间学习了一些东西, ...

  7. Oracle PLSQL游标、游标变量的使用

    参考文章:https://www.cnblogs.com/huyong/archive/2011/05/04/2036377.html 在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实 ...

  8. K8S 上搭建 Redis

    根据需求搭建一个不需要数据持久化,需要密码登录的 Redis mkdir /iba/qa_ibaboss_elk -p cd /iba/qa_ibaboss_elk # 创建一个专用的 namespa ...

  9. java随机数获取

    /**Number One: * 随机数获取公式:(数据类型)(最小值+Math.random()*(最大值-最小值+1)) * 随机数获取公式:(类型)最小值+Math.random()*最大值 * ...

  10. zookeper分布式搭建

    zookeper的安装如下链接 https://www.cnblogs.com/wanerhu/p/11144815.html