Lab2 内存管理(实现细节)
lab2 中的变动
bootloader 的入口发生了改变
bootloader不像lab1那样,直接调用kern_init函数,而是先调用位于lab2/kern/init/entry.S中的kern_entry函数。kern_entry函数的主要任务是为执行kern_init建立一个良好的C语言运行环境(设置堆栈),而且临时建立了一个段映射关系,为之后建立分页机制的过程做一个准备(细节在3.5小节有进一步阐述)。完成这些工作后,才调用kern_init函数。
通过 BIOS 中断获取内存布局有三种方式,都是基于INT 15h中断,分别为88h e801h e820h。但是 并非在所有情况下这三种方式都能工作。在 Linux kernel 里,采用的方法是依次尝试这三 种方法。而在本实验中,我们通过e820h中断获取内存信息。因为e820h中断必须在实模式下使用,所以我们在 bootloader 进入保护模式之前调用这个 BIOS 中断,并且把 e820 映 射结构保存在物理地址0x8000处。
以页为单位管理物理内存
Page的定义在kern/mm/memlayout.h中。以页为单位的物理内存分配管理的实现在kern/default_pmm.[ch]。
首先就是 Page 结构用来描述物理页
+ref 被引用的次数
+flags 状态
+property 算法使用的状态
+page-link 连接其他的自由变量
接下来需要解决两个问题:
管理页级物理内存空间所需的Page结构的内存空间从哪里开始 占多大空间?
空闲内存空间的起始地址在哪里?
首先根据bootloader 给出的内存布局信息找出最大的物理内存地址 maxpa(定义在page_init 中的局部变量), 由于x86 的起始物理内存地址为0, 所以可以得到需要管理的物理页个数为 : npage=maxpa / PGSIZE
这样可以估算出管理页级物理内存空间所需的 Page 结构的空间大小为
sizeof(struct Page) *npage
由于bootloader 加载ucore的结束地址 用全局变量指针end 记录
以上的空间没有被使用,所以我们可以把end按页大小为边界取整后,作为管理页级物理内存空间所需的Page结构的内存空间,记为
pages = (struct Page )ROUNDUP((void )end, PGSIZE);
为了简化起见,从地址0到地址pages+ sizeof(struct Page) * npage)结束的物理内存空间设定为已占用物理内存空间(起始0~640KB的空间是空闲的),地址pages+ sizeof(struct Page) * npage)以上的空间为空闲物理内存空间,这时的空闲空间起始地址为
uintptr_t freemem = PADDR((uintptr_t)pages + sizeof(struct Page) * npage);
for (i = 0; i < npage; i ++) {
SetPageReserved(pages + i);
}
init_memmap(pa2page(begin), (end - begin) / PGSIZE);
其实SetPageReserved只需把物理地址对应的Page结构中的flags标志设置为PG_reserved ,表示这些页已经被使用了,将来不能被用于分配。而init_memmap函数则是把空闲物理页对应的Page结构中的flags和引用计数ref清零,并加到free_area.free_list指向的双向列表中,为将来的空闲页管理做好初始化准备工作。
只实现最简单的内存页分配算法。
下面是内存分配器结构的结论批
struct pmm_manager {
const char name; //物理内存页管理器的名字
void (init)(void); //初始化内存管理器
void (init_memmap)(struct Page base, size_t n); //初始化管理空闲内存页的数据结构
struct Page (alloc_pages)(size_t n); //分配n个物理内存页
void (free_pages)(struct Page base, size_t n); //释放n个物理内存页
size_t (nr_free_pages)(void); //返回当前剩余的空闲页数
void (check)(void); //用于检测分配/释放实现是否正确的辅助函数
};
kern/mm/pmm.h 中定义了一个通用的分配算法的函数列表,用pmm_mamager 表示。 init 函数是用来初始话 free_area 变量的
first_fit 可以重用default_init 函数的实现。
init_memmao 函数需要根据现有的内存情况构建空闲块列表的初始状态
pmm.c 模块
get_pte 获取一个线性地址对应的页表项地址
页表项除去状态位然后 剩下物理地址 根据这个物理地址取出 PPN 在pages 结构中找到对应的页项 或者说 pte2page
get_page 获取一个物理地址对应的页项 会存储这个页表项到第三个参数
page_remove_pte 接受一个页表项 删除 如果对应的页没有引用了 就free 那个一个页 还要将tlb无效化
page_insert 使一个线性地址 被映射到一个页中 , 那个线性地址原先如果已经有映射了 那就取消这个映射
那么还需要最后一个封装
使用 alloc_page 申请得到一个新的页面
使用 page_insert 将这个线性地址插入到对应的pte中去
就是 pgdir_alloc_page
get_pte 的一些细节
输入 pde_t * pgdir uintptr_t la, bool create
取得页目录项地址 pde_t * pde = &pgdir[PDX(la)]
取得页表物理地址 PDE_ADDR(*pde)
取得页表的内核虚拟地址 KADDR(PDE_ADDR(*pde))
取得页表项的虚拟地址 &((pte_t )KADDR(PDE_ADDR(pde)))[PTX(la )]
Lab2 内存管理(实现细节)的更多相关文章
- MIT6.828 Lab2 内存管理
Lab2 0. 任务介绍 你将编写一个内存管理代码.主要分为两大部分.分别对物理内存和虚拟内存的管理. 对于物理内存,每次分配内存分配器会为你分配4096bytes.也称为一个页(在大部分操作系统中一 ...
- ChCore Lab2 内存管理 实验笔记
本文为上海交大 ipads 研究所陈海波老师等人所著的<现代操作系统:原理与实现>的课程实验(LAB)的学习笔记的第二篇.所有章节的笔记可在此处查看:chcore | 康宇PL's Blo ...
- cocos2dx 内存管理的理解
关于引擎内存管理的细节,网上有大量的详解,这里概括一下: cocos2d-x 的世界是基于 CCObject 类构建的,所以内存管理的本质就是管理一个个 CCObject. //CCObject 内部 ...
- 《Effective C++》内存管理
如果global new-hander没有成功配置,会抛出一个std::bad_alloc的exception. #include<iostream> #include<new> ...
- Android 内存管理之优化建议
OOM(OutOfMemory)转:http://hukai.me/android-performance-oom/ 前面我们提到过使用getMemoryClass()的方法可以得到Dalvik He ...
- 从内存管理原理,窥探OS内存管理机制
摘要:本文将从最简单的内存管理原理说起,带大家一起窥探OS的内存管理机制,由此熟悉底层的内存管理机制,写出高效的应用程序. 本文分享自华为云社区<探索OS的内存管理原理>,作者:元闰子 . ...
- [置顶] 内存管理一点也不神秘————手绘iOS内存管理细节
今天给大家带来的一篇手绘风格博文<内存管理一点也不神秘> 每当我们程序执行alloc/new/copy/mutableCopy的时候,当我们执行release的时候,当我们执行retain ...
- set方法的内存管理细节
一.多个对象之间的内存管理 1.你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作) 2.你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次releas ...
- iOS- 非ARC的项目内存管理细节详解(实战)
1.前言 接上文:iOS- 如何将非ARC的项目转换成ARC项目(实战) 2.内存管理时相关的配置 当我们把将非ARC的内存管理都管理好后,发现在做有些操作的时候内存还是在一直的缓慢增加 比如做一个最 ...
随机推荐
- MySQL其他和备份
目录 事务 存储引擎 InnoDB存储引擎 数据存储形式 锁的粒度 事务 数据的存储特点 MyISAM存储引擎 数据存储形式 锁的粒度 事务 数据的存储特点 其他 对比与选择 视图 触发器 存储过程 ...
- python 继承中的__init__
如果子类不重写__init__, 实例化子类时,会自动调用父类定义的__init__ 如果子类要重写__init__,实例化子类,就不会调用父类已经定义的__init__ 所以如果想要扩充父类,需要显 ...
- 19-10-31-B
%%%B哥 ZJ一下: 开题. 发现 语文考试???? 我不认识XD.老帅哥救我! 后来…… 对什么取模??? 什么玩意??输入什么?? 满足啥?? 全是亻 啊! 后来才知道是题楔×了 不管了. 然后 ...
- 在Linux中使用selenium(环境部署)
1.安装chrome 用下面的命令安装Google Chrome yum install https://dl.google.com/linux/direct/google-chrome-stable ...
- 服务器的tomcat调优和jvm调化
下面讲述的是tomcat的优化,及jvm的优化 Tomcat 的缺省配置是不能稳定长期运行的,也就是不适合生产环境,它会死机,让你不断重新启动,甚至在午夜时分唤醒你.对于操作系统优化来说,是尽可能的增 ...
- 图解nginx配置文件nginx.conf
1. 一个server表示一个虚拟主机, 说白了就是网站, 一个nginx可以有多个server 2. listen网站监听的端口 3. server_name网站的域名 4. root是网站的相对目 ...
- lc13 Roman to Integer
lc13 Roman to Integer 遇到那六种特殊情况分别-2,-20,-200, 按照罗马数字的规则,每种只可能出现一次.所以只需要考虑一次,用indexOf()即可判断是否出现这几种特殊情 ...
- 廖雪峰Java10加密与安全-4加密算法-2口令加密算法
对称加密key是一个byte数组,如AES256算法的key是一个32字节的数组,普通的加密软件由用户输入加密口令.如果由用户输入口令,进行加密/解密,需要用到PBE算法. 1.PBE:Passwor ...
- Python快速搭建HTTP服务器
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style=&q ...
- AppServer获取参数的方法
AppServer中从APP_PARAM表中根据param_code获取param_value: appManageService.getParamValueByCode(param_code) -- ...