一、内存管理 中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
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文无所谓版权,欢迎转载。