鸽了好久,决定还是把之前做的实验都给记录一下吧orz。

Lab 5 的懒分配(Lazy Allocation)

这个实验主要是为了实现一种内存分配策略。即在进程实际访问内存时才分配物理内存,而不是在调用 sbrk 时立即分配。这可以提高内存利用率,减少不必要的内存浪费。(有点像线段树中的lazy tag 就是 打一个标记,em 你要用,我在给你,不要浪费)。

修改 sbrk 函数

1.只增加进程的大小分配字段 myproc() -> sz; 但是不给他分配实际的物理页面。

2.当进程访问未分配的内存时,会引发page fault。

1
2
3
4
5
6
7
8
9
10
11
12
uint64
sys_sbrk(void)
{
int addr;
int n;
if(argint(0, &n) < 0)
return -1;
addr = myproc()->sz;
myproc()->sz += n;
return addr;
}

处理缺页异常

因为我们修改的sbrk函数 会导致page fault 所以我们需要修改一下处理函数。

  • usertrap 函数中添加代码来处理缺页异常。
  • r_scause() 返回值为 13(加载页错误)或 15(存储/AMO 页错误)时,分配一个物理页并将其映射到引发异常的虚拟地址。

大致思路如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void
usertrap(void)
{
if (r_scause() == 13 || r_scause() == 15) {
uint64 va = r_stval();
uint64 ka = (uint64) kalloc();
if (ka == 0) {
myproc()->killed = 1;
} else {
memset((void*)ka, 0, PGSIZE);
va = PGROUNDDOWN(va);
if (mappages(myproc()->pagetable, va, PGSIZE, ka, PTE_U | PTE_W | PTE_R) != 0) {
kfree((void*)ka);
myproc()->killed = 1;
}
}
} else {
// 处理其他中断
}
}

更新 uvmunmap函数

确保取消映射时不会因为未分配虚拟内存而导致引发panic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{
for (uint64 a = va; a < va + npages * PGSIZE; a += PGSIZE) {
pte_t *pte = walk(pagetable, a, 0);
if (pte == 0 || (*pte & PTE_V) == 0) {
continue;
}
if (do_free) {
uint64 pa = PTE2PA(*pte);
kfree((void*)pa);
}
*pte = 0;
}
}

总结

os 实验是非常有意思的一件事,只有多做,多去查阅资料,擅长使用google or Stack 、Overflow 、copilot ai 等gpt模型 来帮助我们去完成这个实验,在这个时代,做就完事了,加油~