Lab2:物理内存管理
前言
现在内存管理的方法都是非连续内存管理,也就是结合段机制和分页机制
段机制
段地址空间
进程的段地址空间由多个段组成,比如代码段、堆栈段和符号表段等等
段对应一个连续的内存“块”
不同段在物理内存中是分散的二维结构
段访问
首先由CPU读取逻辑地址,逻辑地址由段号和段内偏移组成
通过段寄存器找到相应的段描述符获得段基址
然后由MMU判断长度是否符合,否则就引发内存异常
最后通过段基址和段内偏移找到真实的物理内存
页机制
页机制把真实的物理内存分为大小相同的基本分配单位,叫做页帧,再接着把逻辑地址空间也划分为大小相同的基本分配单位,页和帧的大小必须是一致的,最后再完成从页面到页帧的映射,也就是逻辑地址到物理地址的转换
页和页帧
页帧和段的寻址方式有点像,也就是当前帧的基地址再加上帧内偏移,当前帧的基地址也是由当前的帧号和每一帧的大小确定的
页的寻址也是相同,但是页号不一定等于帧号,所以也就是在页和帧之间还有一层地址映射
页表
页表就是保存了逻辑地址到物理地址之间的映射关系,逻辑地址中保存着页号和页内偏移,到页表中查询页帧最后得到真实的物理地址
每一个页面都会对应一个页表项,页表会随着进程的变化而变化,页表项不仅记录对应的页帧还保存了一些标志:存在位、修改位和引用位
页机制的性能问题
页机制存储管理机制在访问性能方面可能因为每一次的访问地址需要两次访问而造成低效,并且如果页表过大也会造成性能问题
快表
快表就是类似一个缓存机制,将最近访问的页表项缓存到TLB中,这样每次访问都可以先到快表中查询,如果TLB命中就会节省非常大的时间
多级页表
多级页表就是将页表分为树状结构,通过级级查询找到最后的结果,这样就可以减少每级页表的长度
段页式存储管理
段页式顾名思义也就是结合了段机制和页机制,这样就可以结合段机制在内存保护方面的优势和页机制在内存利用率上面的优势
段页式其实也就是在中间多加了一层映射,由段机制产生的线性地址到页表的映射,这样在逻辑地址中存储着段表和页表的偏移地址,也就是段号和页号,然后通过段表查询到页表的地址,再通过页号查询 到真实的物理内存地址
启用分页机制
kern_entry:
# load pa of boot pgdir
movl $REALLOC(__boot_pgdir), %eax
movl %eax, %cr3
# enable paging
movl %cr0, %eax
orl $(CR0_PE | CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_TS | CR0_EM | CR0_MP), %eax
andl $~(CR0_TS | CR0_EM), %eax
movl %eax, %cr0
# update eip
# now, eip = 0x1.....
leal next, %eax
# set eip = KERNBASE + 0x1.....
jmp *%eax
next:
# unmap va 0 ~ 4M, it's temporary mapping
xorl %eax, %eax
movl %eax, __boot_pgdir
# set ebp, esp
movl $0x0, %ebp
# the kernel stack region is from bootstack -- bootstacktop,
# the kernel stack size is KSTACKSIZE (8KB)defined in memlayout.h
movl $bootstacktop, %esp
# now kernel stack is ready , call the first C function
call kern_init
首先要启动分页模式,cr3寄存器就应该存放着一级页表,然后进行分页模式的使能,再做一些准备工作然后跳入kern_init内核初始化
void
pmm_init(void) {
boot_cr3 = PADDR(boot_pgdir);
init_pmm_manager();
page_init();
check_alloc_page();
check_pgdir();
static_assert(KERNBASE % PTSIZE == 0 && KERNTOP % PTSIZE == 0);
boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_P | PTE_W;
boot_map_segment(boot_pgdir, KERNBASE, KMEMSIZE, 0, PTE_W);
gdt_init();
check_boot_pgdir();
print_pgdir();
}
- 先定义物理内存管理的各个函数
- 检测物理内存空间,保留已使用的内存,然后使用pmm-> init_memmap创建空闲页面列表
- 映射物理内存地址到线性地址
- 重新加载全局描述符表
页机制的代码实现
以页为单位来进行内存的分配
struct Page {
int ref;
uint32_t flags;
unsigned int property;
list_entry_t page_link;
};
ref: ref作为页的引用次数
flags: 标识当前页的使用状态,比如如果这个页被内核使用那么它就是保留状态的
property: 标识当前可用的连续块的大小,这个时候这个页是作为这些空闲块的开始地址的
page_link: 空闲块的链表结构
static void
default_init_memmap(struct Page *base, size_t n) {
assert(n > 0);
struct Page *p = base;
for (;p != base + n; p ++) {
assert(PageReserved(p));
p->flags = 0;
SetPageProperty(p);
p->property = 0;
set_page_ref(p, 0);
list_add_before(&free_list, &(p->page_link));
}
nr_free += n;
base->property = n;
}
init_memmap是进行内存的初始化工作,主要就是设置标志位和引用数和加入空闲队列中
static struct Page *
default_alloc_pages(size_t n) {
assert(n > 0);
if (n > nr_free) {
return NULL;
}
list_entry_t *le, *len;
le = &free_list;
while ((le=list_next(le)) != &free_list) {
struct Page *p = le2page(le, page_link);
if (p->property >= n) {
int i;
for (i = 0; i < n; i ++) {
len = list_next(le);
struct Page *pp = le2page(le, page_link);
SetPageReserved(pp);
ClearPageProperty(pp);
list_del(le);//从空闲页链表中删除这个双向链表指针
le = len;
}
if(p->property > n){
(le2page(le, page_link))->property = p->property - n;//如果选中的第一个连续的块大于n,只取其中的大小为n的块
}
ClearPageProperty(p);
SetPageReserved(p);
nr_free -= n;//当前空闲页的数目减n
return p;
}
}
return NULL;
}
alloc_pages是进行以页为单位进行内存的分配,用的是最简单的First-fit算法,也就是从空闲队列中找到第一个可用的块就直接进行分配,然后如果这个块大于需要分配的内存大小,那就进行切割
static void
default_free_pages(struct Page *base, size_t n) {
assert(n > 0);
struct Page *p = base;
for (; p != base + n; p ++) {
assert(!PageReserved(p) && !PageProperty(p));
p->flags = 0;
set_page_ref(p, 0);
}
base->property = n;
SetPageProperty(base);
list_entry_t *le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
le = list_next(le);
// TODO: optimize
if (base + base->property == p) {
base->property += p->property;
ClearPageProperty(p);
list_del(&(p->page_link));
}
else if (p + p->property == base) {
p->property += base->property;
ClearPageProperty(base);
base = p;
list_del(&(p->page_link));
}
}
nr_free += n;
le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
if (base + base->property <= p) {
assert(base + base->property != p);
break;
}
le = list_next(le);
}
list_add_before(le, &(base->page_link));
}
free_pages是alloc_page的逆过程,一样是先设置一些标志位,然后再遍历空闲队列进行空闲块的合并,再重新入队
Lab2:物理内存管理的更多相关文章
- ucore操作系统学习笔记(二) ucore lab2物理内存管理分析
一.lab2物理内存管理介绍 操作系统的一个主要职责是管理硬件资源,并向应用程序提供具有良好抽象的接口来使用这些资源. 而内存作为重要的计算机硬件资源,也必然需要被操作系统统一的管理.最初没有操作系统 ...
- ucore lab2 物理内存管理 学习笔记
总的来讲把的LAB1代码逻辑理顺后再往后学就轻松了一大截.LAB2过遍课程视频,再多翻翻实验指导书基本上就没遇到啥大坎儿.对这节学得东西做个总结就是一张图: 练习0:填写已有实验 本实验依赖实验1.请 ...
- 《Tsinghua oc mooc》第5~7讲 物理内存管理
资源 OS2018Spring课程资料首页 uCore OS在线实验指导书 ucore实验基准源代码 MOOC OS习题集 OS课堂练习 Piazza问答平台 暂时无法注册 疑问 段式内存管理中,逻辑 ...
- ChCore Lab2 内存管理 实验笔记
本文为上海交大 ipads 研究所陈海波老师等人所著的<现代操作系统:原理与实现>的课程实验(LAB)的学习笔记的第二篇.所有章节的笔记可在此处查看:chcore | 康宇PL's Blo ...
- LInux中的物理内存管理
2017-02-23 一.伙伴系统 LInux下用伙伴系统管理物理内存页,伙伴系统得益于其良好的算法,一定程度上可以避免外部碎片为何这么说?先回顾下Linux下虚拟地址空间的分布. 在X86架构下,系 ...
- Linux内存:物理内存管理概述
内存中的物理内存管理 概述 一般来说,linux内核一般将处理器的虚拟地址空间划分为2部分.底部比较大的部分用于用户进程,顶部则专用于内核. 在IA-32系统上,地址空间在用户进程和内核之间划分的典型 ...
- Lab2 内存管理(实现细节)
lab2 中的变动 bootloader 的入口发生了改变 bootloader不像lab1那样,直接调用kern_init函数,而是先调用位于lab2/kern/init/entry.S中的kern ...
- MIT6.828 Lab2 内存管理
Lab2 0. 任务介绍 你将编写一个内存管理代码.主要分为两大部分.分别对物理内存和虚拟内存的管理. 对于物理内存,每次分配内存分配器会为你分配4096bytes.也称为一个页(在大部分操作系统中一 ...
- Linux下的物理内存管理2-slab缓存的管理
2017-03-02 在Linux下的物理内存管理中,对SLAB机制大致做了介绍,对SLAB管理结构对象也做了介绍,但是对于小内存块的分配没有介绍,本节重点介绍下slab对小内存块的管理. 内核中使用 ...
随机推荐
- 关于ipad设备滚动条无法滚动的解决办法
天做一个功能在ipad设备上滚动条无法滚动,于是百度了下,在需要产生滚动的div上面加入以下css(-webkit-overflow-scrolling:touch,overfolw:scroll), ...
- office2016下载安装
https://jingyan.baidu.com/article/359911f5acfa4357fe030631.html
- 性能监控工具的配置及使用 - Spotlight On Oracle(oracle)
一. Spotlight On Oracle(oracle)1.1. 工具简介Spotlight是一个强有力的Oracle数据库实时性能诊断工具,提供了一个直观的.可视化的数据库活动展现.S ...
- Dr. Memory Quickstart Instructions in Chinese
For similar insructions in English, please see RPI CSCI1200 instructions. 程序内存调试 程序内存错误有很多种,比如内存访问错误 ...
- js中数组的迭代方法
1.forEach 让数组的每一项做一件事 var arr = [1,2,3,4,5] arr.forEach(function(item,index){ console.log(item) }) 2 ...
- Python渗透测试工具库
漏洞及渗透练习平台 WebGoat漏洞练习平台: https://github.com/WebGoat/WebGoat webgoat-legacy漏洞练习平台: https://github.com ...
- 面试题:android用户注册代码 密码需要加密传输吗
答案是肯定的,至少比明文好 客户端注册和登录的时候:一个可行的方法是,客户端提交 md5(password) 密码(如上所述,此方法只是简单保护了密码,是可能被查表获取密码的). 注册的时候:服务端数 ...
- Class版本号和Java版本对应关系
1.背景 版本号不对,会报错,如下 2.版本对应情况 JDK 1.8 = 52 JDK 1.7 = 51 JDK 1.6 =50 JDK 1.5 = 49 JDK 1.4 = 48 JDK 1. ...
- 【学习笔记】大数据技术原理与应用(MOOC视频、厦门大学林子雨)
1 大数据概述 大数据特性:4v volume velocity variety value 即大量化.快速化.多样化.价值密度低 数据量大:大数据摩尔定律 快速化:从数据的生成到消耗,时间窗口小,可 ...
- Ubuntu18.04启动后一个光标在左上角闪动
1.在实验室服务器上安装Ubuntu18.04后,启动后能够进入grub,但选择Ubuntu后出现只有左上角一个光标在闪但是进不去系统的现象. 2.重新启动选择进入recovery mode,出现如下 ...