1. 物理页申请(allocation)
核心算法是:Binary Buddy Allocator.
1. 空闲块管理
每个zone有一个free_area数组, 第0个元素表示的块大小是1个页, 第1个元素表示的块大小是2个页...最大的块大小是512个页.
每个区有一个bitmap, 每一位用来记载一对buddy的使用状态, 如果bit是0, 表示那对page(两页)都是full or free. 如果bit是1, 表示只有其中一页是在用.
2. 申请页
页申请的核心调用是: __alloc_pages(). 页申请顺序如下:
首先找最大能符合的块, 如果一个空闲块不能满足, 更高一级的块将分割成2个buddy, 一个被占用, 一个放入低一级的freelist.
当块被释放时, 检查每对buddy, 如果两者都空闲, 把他们合并到更高一级的块数组里去, 同时放入更高一级的freelist. 如果一个buddy还在被用, 那此块将加入到当前级的freelist.
如果一个zone已经没有足够空闲页,而且又需要分配,那申请将退到下一级,一般顺序是:ZONE_HIGHMEM --> ZONE_NORMAL --> ZONE_DMA. 如果空闲页击中pages_low门限,kswapd将开始释放页。
3. 释放页
核心调用是: __free_pages_ok(). 当一个buddy释放时,尽可能立即合并buddy。有一种不理想的情况是,在最坏的情况下,在很多合并发生之后,立即有发生切割,在相同的块上面。
4. Get Free Page(GFP) Flags
GFP标志决定了VM分配器和kswapd对页的申请和释放的工作方式。
__GFP_DMA, __GFP_HIGHMEM, __GFP_WAIT, __GFP_HIGH, __GFP_IO, __GFP_HIGHIO, __GFP_FS.
5. 进程Flags
进程可以设置标志,来决定分配器的行为方式。
GFP_ATOMIC, GFP_NOIO, GFP_NOHIGHIO, GFP_NOFS, GFP_KERNEL, GFP_USER, GFP_HIGHUSER, GFP_NFS, GFP_KSWAPD.
6. 避免碎片
外部碎片: 因为所有可用的内存只存在于小块,分配器无力满足分配请求。
内部碎片: 是指所浪费的空间,由于大的块用于分配满足小的内存请求。
内部碎片的容易出现,而且破坏力严重,可以看到的是,单靠buddy系统来解决,没有明显的效果,可以解决这个问题的方法是综合slab分配器的使用。
Reference: <<Understanding the Linux Virtual Memory Manager>>
(待续)