linux 伙伴系统
什么叫做伙伴,需要满足三个条件
1 page sieze 相等
2 地址是连续的
3 必须是同一个大块里面分配出来的
伙伴系统的分割
伙伴系统的合并
迁移类型
迁移类型 | 描述 | 例子 |
---|---|---|
UNMOVEBLE 不可移动页面 | 在内存中规定的位置不能移动到其他的地方 | 内核自身使用的内存,比如说GFP_KERNEL分配的 |
MOVEBLE 可移动页面 | 可以随意移动 | malloc分配的匿名页面 |
RECLAIMABLE 可回收的页面 | 不能直接移动,但是可以删除 | 映射自文件的page cache |
行为修饰符
标志 | 描述 |
---|---|
GFP_WAIT | 分配器可以睡眠 |
GFP_HIGH | 分配器可以访问紧急的内存池 |
GFP_IO | 不能直接移动,但可以删除 |
GFP_FS | 分配器可以启动文件系统IO |
GFP_REPEAT | 在分配失败的时候重复尝试 |
GFP_REPEAT | 分配失败的时候重复进行分配,直到分配成功为止 |
GFP_NOFAIL | 分配失败时不允许再尝试 |
zone修饰符
标志 | 描述 |
---|---|
GFP_DMA | 从ZONE_DMA中分配内存 |
GFP_HIGHMEM | 可以从ZONE_HIGHMEM或者ZONE_NORMAL中分配 |
常用的分配标志
标志 | 描述 |
---|---|
GFP_ATOMIC | 分配过程不允许睡眠,通常用在中断处理程序、下半部、持有自旋锁等不能睡眠的地方 |
GFP_KERNEL | 常规的内存分配方式,可以睡眠。 |
GFP_USER | 常用于用户进程分配内存 |
GFP_HIGHUSER | 需要从ZONE_HIGHMEM开始进行分配,也是常用于用户进程分配内存 |
GFP_NOIO | 分配可以阻塞,但不会启动磁盘IO |
GFP_NOFS | 可以阻塞,可以启动磁盘,但不会启动文件系统操作 |
gfp_mask zone 迁移类型的关系
系统会优先使用ZONE_HIGHMEM,然后才是ZONE_NORMAL
怎么通过GFP知道需要从那个迁移类型中分配?
static inline int gfpflags_to_migratetype(const gfp_t gfp_flags)
{
VM_WARN_ON((gfp_flags & GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK);
BUILD_BUG_ON((1UL << GFP_MOVABLE_SHIFT) != ___GFP_MOVABLE);
BUILD_BUG_ON((___GFP_MOVABLE >> GFP_MOVABLE_SHIFT) != MIGRATE_MOVABLE);
if (unlikely(page_group_by_mobility_disabled))
return MIGRATE_UNMOVABLE;
/* Group based on mobility */
return (gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT;
}
per-cpu页面分配
内核经常请求和释放单个页框,网卡驱动
在分配和释放页面的使用需要申请 zone->lock
为了提高单个页框效率,内核建立了per-cpu页面高速缓存池,高速缓存池里面存的是若干个预先就已经分配好的页框.
如果需要请求单个页框,就可以直接去高速缓存池获取,不需要申请锁,也不需要进行页框分配操作.极大的提高了单个页面分配的效率
struct per_cpu_pages {
int count; /* number of pages in the list */
int high; /* high watermark, emptying needed */
int batch; /* chunk size for buddy add/remove */
/* Lists of pages, one per migrate type stored on the pcp-lists */
struct list_head lists[MIGRATE_PCPTYPES];
};
struct zone {
/* Read-mostly fields */
/*读敏感域*/
/* zone watermarks, access with *_wmark_pages(zone) macros */
unsigned long _watermark[NR_WMARK];//水位管理 high low mini
unsigned long watermark_boost;
unsigned long nr_reserved_highatomic;
/*
* We don't know if the memory that we're going to allocate will be
* freeable or/and it will be released eventually, so to avoid totally
* wasting several GB of ram we must reserve some of the lower zone
* memory (otherwise we risk to run OOM on the lower zones despite
* there being tons of freeable ram on the higher zones). This array is
* recalculated at runtime if the sysctl_lowmem_reserve_ratio sysctl
* changes.
*/
long lowmem_reserve[MAX_NR_ZONES];
/*管理zone 常用信息*/
struct pglist_data *zone_pgdat;
struct per_cpu_pageset __percpu *pageset;
};