XV6学习(7)Lab lazy
代码在github上。
这一个实验是要利用缺页异常来实现懒分配(lazy allocation)。用户态程序通过sbrk
系统调用来在堆上分配内存,而sbrk
则会通过kalloc
函数来申请内存页面,之后将页面映射到页表当中。
当申请小的空间时,上述过程是没有问题的。但是如果当进程一次申请很大的空间,如数GB的空间,再使用上述策略来一页页地申请映射的话就会非常的慢(1GB/4KB=262,144)。这时候就引入了lazy allocation技术,当调用sbrk
时不进行页面的申请映射,而是仅仅增大堆的大小,当实际访问页面时,就会触发缺页异常,此时再申请一个页面并映射到页表中,这是再次执行触发缺页异常的代码就可以正常读写内存了。
通过lazy allocation技术,就可以将申请页面的开销平摊到读写内存当中去,在sbrk
中进行大量内存页面申请的开销是不可以接受的,但是将代价平摊到读写操作当中去就可以接受了。
总体来说这一个实验的难度并不大,理解了上一个trap的实验以及缺页异常就能比较轻松地完成了。
1|0Eliminate allocation from sbrk() (easy)
这一个就是要修改sbrk
函数,使其不调用growproc
函数进行页面分配,关键就是p->sz += n
将堆大小增大,然后注释掉growproc
。if(n < 0)
是后面部分的内容。
2|0Lazy allocation (moderate)
接下来就是真正实现Lazy allocation:当系统发生缺页异常时,就会进入到usertrap
函数中,此时scause
寄存器保存的是异常原因(13为page load fault,15为page write fault),stval
是引发缺页异常的地址。
在usertrap
判断scause
为13或15后,就可以读取stval
获取引发异常的地址,之后调用lazy_alloc
对该地址的页面进行分配即可。在这里不需要进行p->trapframe->epc += 4
操作,因为我们要返回发生异常的那条指令并重新执行。
在lazy_alloc
函数中,首先判断地址是否合法,之后通过PGROUNDDOWN
宏获取对应页面的起始地址,然后调用kalloc
分配页面,memset
将页面内容置0,最后调用mappages
将页面映射到页表中去。
3|0Lazytests and Usertests (moderate)
这一部分就是要强化上面写的的lazy allocation,使其能在一些特殊情况下工作。
Handle negative sbrk() arguments.
这一个就是在上面的sys_sbrk
函数中的if(n < 0)
部分,当参数为负数时,调用uvmdealloc
取消分配。
Kill a process if it page-faults on a virtual memory address higher than any allocated with sbrk().
这一个即lazy_alloc
函数中的addr >= p->sz
部分,当访问的地址大于堆的大小时就说明访问了非法地址,注意这里是>=
而不是>
。
Handle the parent-to-child memory copy in fork() correctly.
在fork
函数中通过uvmcopy
进行地址空间的拷贝,我们只要将其中panic
的部分改为continue
就行了,当页表项不存在时并不是说明出了问题,直接跳过就可以了。
Handle the case in which a process passes a valid address from sbrk() to a system call such as read or write, but the memory for that address has not yet been allocated.
当进程通过read
或write
等系统调用访问未分配页面的地址时,并不会通过页表硬件来访问,也就是说不会发生缺页异常;在内核态时是通过walkaddr
来访问用户页表的,因此在这里也要对缺页的情况进行处理。
当出现pte == 0 || (*pte & PTE_V) == 0
时,就说明发生了缺页,这时只要调用lazy_alloc
进行分配,之后再次使用walk
就能正确得到页表项了。
Handle out-of-memory correctly: if kalloc() fails in the page fault handler, kill the current process.
当kalloc
失败时,lazy_alloc
就会返回负值,此时判断返回值然后p->killed = 1
就行了。
Handle faults on the invalid page below the user stack.
这一个可以通过addr < p->trapframe->sp
判断,当地址小于栈顶地址时就说明发生了非法访问。
__EOF__

本文链接:https://www.cnblogs.com/weijunji/p/14338483.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律