介绍
写在前面
这个实验主要是写内存的懒分配(Lazy page allocation)应该是目前为止最简单的了?!实验说明地址在Lab: xv6 lazy page allocation,我的代码在 github。
断断续续的做也没用多长时间,。需要的知识比较简单,可能会比较考验 debug 的能力,不过参考一下网上的经验,还是很容易解决的。
前置知识
主要的知识就是内存分配为什么需要设置成懒分配(Lazy page allocation)的模式。主要是因为进程在申请内存时,很难精确地知道所需要的内存多大,因此,进程倾向于申请多于所需要的内存。这样会导致一个问题:有些内存可能一直不会使用,申请了很多内存但是使用的很少。懒分配模式就是解决这样一个问题。解决方法是:分配内存时,只增大进程的内存空间字段值,但并不实际进行内存分配;当该内存段需要使用时,会发现找不到内存页,抛出 page fault 中断,这时再进行物理内存的分配,然后重新执行指令。
最主要的一点,需要注意的是,进程的地址空间是连续的,从 0 开始到 MAXVA,如下图所示:

进程创建时,首先为可执行程序分配代码段(text)和数据段(data),然后分配一个无效的页 guard page 用于防止栈溢出。接下来分配进程用户空间栈,xv6 栈的大小是4096,刚好对应一页内存。值得注意的是,栈的生长方向是向下的,sp 是栈指针,初始时指向栈底,即大的地址位置。在栈生长时,栈指针(sp)减小。栈的上面是堆(heap),堆的大小是动态分配的,进程初始化时,堆大小为 0,p->sz 指针指向栈底位置。
实验内容
三个任务的目的都是实现一个功能,递进式实现,有些代码需要在三个任务中不断更改。建议做实验之前看一下这节对应的课程,课程内讲了该怎么更改代码,与实验有很大的关系。
任务一(Eliminate allocation from sbrk())
任务一的目的就是更改 kernel/sysproc.c 中的 sys_sbrk() 函数,把原来只要申请就分配的逻辑改成申请时仅进行标注,即更改进程的 sz 字段。其实只要对 sz 进行增加就能完成这部分的更改,但后面的任务还需要更改这个函数,直接放上最终版:
uint64
sys_sbrk(void)
{
int addr;
int n;
if(argint(0, &n) < 0)
return -1;
struct proc *p = myproc();
addr = p->sz;
//if (addr + n < 0) return -1;
if (addr + n >= MAXVA || addr + n <= 0)
return addr;
p->sz = addr + n;
//if(growproc(n) < 0)
// return -1;
if(n < 0)
uvmdealloc(p->pagetable, addr, p->sz);
return addr;
}
这里有三点需要注意的:
- 将 p->sz 增加 n,这也是任务一的要求。
- 如果 n 是负数,则对其对应的内存进行释放(仿照 proc.c 中的 growproc 函数写就行)。
- 判断堆的空间大小。不能超过 MAXVA,也不能释放小于 0 的地址空间。
如果直接运行 echo hi 命令会报错,因为我们还没写分配内存的逻辑,这是下面任务的内容。
任务二(Lazy allocation)
第一步,处理中断,分配内存
仿照上一个实验中的中断处理操作,在 kernel/trap.c 中,找到中断处理的逻辑进行更改。
系统调用的中断码是 8,page fault 的中断码是 13 和 15。因此,这里我们对 r_scause() 中断原因进行判断,如果是 13 或是 15,则说明没有找到地址。错误的虚拟地址被保存在了 STVAL 寄存器中,我们取出该地址进行分配。如果申请物理地址没成功或者虚拟地址超出范围了,那么杀掉进程,代码如下:
else if((which_dev = devintr()) != 0){
// ok
} else if(

本文介绍了XV6操作系统中实现懒分配(Lazypageallocation)的实验过程,包括修改sys_sbrk()函数以延迟内存分配,处理pagefault中断以按需分配内存,以及解决uvmunmap和walkaddr的异常情况。实验分为三个任务,最终通过所有测试用例,实现了一个完整的懒分配内存管理系统。
最低0.47元/天 解锁文章
3438

被折叠的 条评论
为什么被折叠?



