本文将在JOS
上实现连续内存、释放,提供内核的kmalloc
与kfree
,并在分配frambuffer
的时候进行测试。
Github : https://github.com/He11oLiu/MOS
在lab2
中实现的内存管理只是针对单页建立freelist
,list
中用链表连接起来的都是代表单页的结构体struct PageInfo
。且每次释放页,都是丢在这个free_list
的头。这样有几个问题:
- 不能分配大于
4k
的连续空间(后面做frambuf
的时候要用到) - 不断地加到空闲列表的头会使内存空间十分的混乱。不利于内存管理。
所以先要设计一种能够支持分配连续空间的机制。
一种简单的实现
最简单的想法就是保持现有的不动,freelist
保证从高地址到低地址。
这要求在page_free
的时候做一下手脚,放到合适的位置。
在npages_alloc
的时候,找到连续的空闲的页即可。
Free
既然最主要的是在free
的时候需要维护freelist
按照地址的大小排列,那么就先简单将page_free
重新写一下,找到合适的位置再进行插入操作。
特别要注意是否刚好应该插入到free list
的头的情况:
如果刚好是最高的地址,那么就需要修改page_free_list
if (page2pa(page_free_list) < page2pa(pp))
{
cur = page_free_list;
page_free_list = pp;
pp->pp_link = cur;
return;
}
否则需要遍历来查找位置插入
cur = page_free_list;
prev = page_free_list;
while (page2pa(cur) > page2pa(pp))
{
prev = cur;
if ((cur = cur->pp_link) == NULL)
break;
}
prev->pp_link = pp;
pp->pp_link = cur;
写完简单的free
之后,我们可以确保freelist
的顺序问题了。
npages_alloc
再来看主要的alloc
,其核心思想则是检查是否刚好有连续的空间能够分配出去,这里用consecutive
来记录累计连续的页数。
通过pageInfo
在pages
的数组的偏移即可知道其对应的地址,如果这个偏移是连续的,则代表着一块连续的空间:
(int)(cur - pages) == (int)(prev - pages) - 1
其中cur
为当前遍历到的pageInfo
,而prev
是上次遍历的,通过上面的表达式可以判断是否为连续。
如果找到了合适的一块空间,则需要
维护
freelist
,将这块空间前的最后一页连接到分配走的后面一页。同样注意是否有存在需要换头的情况
if (pp == page_free_list) page_free_list = cur; else pp_prev->pp_link = cur;
初始化页属性与空间
if (alloc_flags & ALLOC_ZERO) memset(page2kva(prev), 0, n * PGSIZE); // clear pp link