页面分配算法
如果要在ucore中实现连续物理内存分配算法,则需要考虑的事情比较多,相对课本上的物理内存分配算法描述要复杂不少。下面介绍一下如果要实现一个FirstFit内存分配算法的大致流程。原理FirstFit内存分配算法上很简单,但要在ucore中实现,需要充分了解和利用ucore已有的数据结构和相关操作、关键的一些全局变量等。
关键数据结构与变量
first_fit
分配算法需要维护一个查找有序(地址按从小到大排列)空闲块(以页为最小单位的连续地址空间)的数据结构,而双向链表是一个很好的选择。
libs/list.h
定义了可挂接任意元素的通用双向链表结构和对应的操作,所以需要了解如何使用这个文件提供的各种函数,从而可以完成对双向链表的初始化/插入/删除等。
显然,我们可以通过free_area_t
数据结构来完成对空闲块的管理。而default_pmm.c
中定义的free_area
变量就是干这个事情的。
kern/mm/pmm.h
中定义了一个通用的分配算法的函数列表,用pmm_manager
表示。其中init
函数就是用来初始化free_area
变量的, first_fit
分配算法可直接重用default_init
函数的实现。init_memmap
函数需要根据现有的内存情况构建空闲块列表的初始状态。何时应该执行这个函数呢?
通过分析代码,可以知道:
所以,default_init_memmap
需要根据page_init
函数中传递过来的参数(某个连续地址的空闲块的起始页,页个数)来建立一个连续内存空闲块的双向链表。这里有一个假定page_init
函数是按地址从小到大的顺序传来的连续内存空闲块的。链表头是free_area.free_list
,链表项是Page数据结构的base->page_link
。这样我们就依靠Page数据结构中的成员变量page_link
形成了连续内存空闲块列表。
设计实现
default_init_memmap
函数将根据每个物理页帧的情况来建立空闲页链表,且空闲页块应该是根据地址高低形成一个有序链表。根据上述变量的定义,default_init_memmap
可大致实现如下:
如果要分配一个页,那要考虑哪些呢?这里就需要考虑实现default_alloc_pages
函数,注意参数n表示要分配n个页。另外,需要注意实现时尽量多考虑一些边界情况,这样确保软件的鲁棒性。比如
这样可以确保分配不会超出范围。也可加一些 assert
函数,在有错误出现时,能够迅速发现。比如 n应该大于0,我们就可以加上
这样在n<=0的情况下,ucore会迅速报错。firstfit
需要从空闲链表头开始查找最小的地址,通过list_next
找到下一个空闲块元素,通过le2page
宏可以由链表元素获得对应的Page
指针p
。通过p->property
可以了解此空闲块的大小。如果>=n,这就找到了!如果<n,则list_next,继续查找。直到list_next== &free_list
,这表示找完了一遍了。找到后,就要从新组织空闲块,然后把找到的page返回。所以default_alloc_pages
可大致实现如下:
default_free_pages
函数的实现其实是default_alloc_pages
的逆过程,不过需要考虑空闲块的合并问题。这里就不再细讲了。自行阅读代码。
看完了first fit算法了,就需要自己实现best fit算法了噢,思路都是一样的,依葫芦画瓢。
最后更新于