内存管理十一 MIGRATE_HIGHATOMIC类型页面

一、内存管理 中migration type中MIGRATE_HIGHATOMIC介绍:

  在系统运行一段时间后,会出现大量内存碎片,会导致高阶页块(high-order page)的分配失败。

为了避免,减轻这种情况,创建了MIGRATE_HIGHATOMIC类型的页面。在此后的分配中,只有

当相同的高阶,并拥有高级分配权限时,才会分配这样的页块。当分配单个页框失败时,这样的页块

会被回收,类型发生变化。

//kernel-4.9/mm/page_alloc.c
static void show_migration_types(unsigned char type)
{
	static const char types[MIGRATE_TYPES] = {
		[MIGRATE_UNMOVABLE]	= 'U',
		[MIGRATE_MOVABLE]	= 'M',
		[MIGRATE_RECLAIMABLE]	= 'E',
		[MIGRATE_HIGHATOMIC]	= 'H',
#ifdef CONFIG_CMA
		[MIGRATE_CMA]		= 'C',
#endif
#ifdef CONFIG_MEMORY_ISOLATION
		[MIGRATE_ISOLATE]	= 'I',
#endif
	};
......
}

二、MIGRATE_HIGHATOMIC类型页面的保留及回收:

1、在系统中,保存的MIGRATE_HIGHATOMIC类型的页面的大小通过如下函数定义,也就是

对应zone的1/100加上一个pageblock的大小(4MB):

/*
 * Reserve a pageblock for exclusive use of high-order atomic allocations if
 * there are no empty page blocks that contain a page with a suitable order
 */
static void reserve_highatomic_pageblock(struct page *page, struct zone *zone,
				unsigned int alloc_order)
{
	int mt;
	unsigned long max_managed, flags;

	/*
	 * Limit the number reserved to 1 pageblock or roughly 1% of a zone.
	 * Check is race-prone but harmless.
	 */
	max_managed = (zone->managed_pages / 100) + pageblock_nr_pages;
	if (zone->nr_reserved_highatomic >= max_managed)
		return;
......
}

2、在内存紧张或者内存碎片较多时,出现内存分配fail时会回收这部分内存:

__alloc_pages_slowpath -> __alloc_pages_direct_reclaim

/* The really slow allocator path where we enter direct reclaim */
static inline struct page *
__alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,
		unsigned int alloc_flags, const struct alloc_context *ac,
		unsigned long *did_some_progress)
{
......
	if (!page && !drained) {
		unreserve_highatomic_pageblock(ac);
		drain_all_pages(NULL);
		drained = true;
		goto retry;
	}

	return page;
}
/*
 * Used when an allocation is about to fail under memory pressure. This
 * potentially hurts the reliability of high-order allocations when under
 * intense memory pressure but failed atomic allocations should be easier
 * to recover from than an OOM.
 */
static void unreserve_highatomic_pageblock(const struct alloc_context *ac)
{
	for_each_zone_zonelist_nodemask(zone, z, zonelist, ac->high_zoneidx,
								ac->nodemask) {
		/* Preserve at least one pageblock */
		if (zone->nr_reserved_highatomic <= pageblock_nr_pages)
			continue;
......
}

  可以看到上面最小的MIGRATE_HIGHATOMIC页面预留大小是一个pageblock(4Mb)。

3、具体问题分析:

[44021.651363]  (0)[5355:UsbFfs-worker]UsbFfs-worker invoked oom-killer: 
gfp_mask=0x24040c0(GFP_KERNEL|__GFP_COMP), nodemask=0, order=3, oom_score_adj=-1000

可以看到上面申请2^3 * 4KB时出现oom,此时看对应的memory 情况:

[44021.651680] Normal free:81728kB min:2768kB low:6460kB high:7152kB active_anon:48kB
inactive_anon:64kB active_file:520kB inactive_file:564kB unevictable:0kB writepending:580kB
present:528128kB managed:480876kB mlocked:0kB slab_reclaimable:28760kB slab_unreclaimable:104504kB kernel_stack:6312kB pagetables:8396kB bounce:0kB free_pcp:724kB
 local_pcp:396kB free_cma:0kB

Normal zone的剩余内存还有81MB,内存剩余充足为什么会出现oom呢,继续向下看下:

[44021.651717] Normal: 8896*4kB (UMEH) 3964*8kB (UMEH) 648*16kB (UMEH) 1*32kB (H) 1*64kB (H) 
1*128kB (H) 1*256kB (H) 1*512kB (H) 1*1024kB (H) 1*2048kB (H) 0*4096kB = 81728kB

可以看到剩余的内存都是MIGRATE_HIGHATOMIC类型和其他的类型,但申请的内存为__GFP_RECLAIM("E"),

此时已经没有符合要求的类型的内存,故出现fail,此问题是内存碎片化导致:

kernel-4.9/include/linux/gfp.h
#define GFP_KERNEL	(__GFP_RECLAIM | __GFP_IO | __GFP_FS)

作者:frank_zyp 
您的支持是对博主最大的鼓励,感谢您的认真阅读。 
本文无所谓版权,欢迎转载。

发布了59 篇原创文章 · 获赞 80 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/frank_zyp/article/details/89249469