Linux内核中用GFP_ATOMIC申请内存意味着什么

本文目的
本文补充校正一些linux内核开发者关于gfp_atomic的认知不完整的地方,阐述gfp_atomic与free内存watermark的关系,并明确什么时候应该用gfp_atomic申请内存。目录:
1. gfp_atomic vs. gfp_kernel
2. 内存水位,pf_memalloc和gfp_atomic
3. 何时使用gfp_atomic(一个patch分析)
gfp_atomic vs. gfp_kernel
我们都知道,在中断、软中断、spinlock等原子上下文里面,申请内存,应该使用gfp_atomic标记,譬如内核中有大量的kmalloc/gfp_atomic的例子:
对于不可睡眠的上下文,如果我们用常规的gfp_kernel这样的标记去申请内存,可能引发直接的内存reclaim,从而引起睡眠,所以gfp_kernel这种标记只适合进程上下文调用:
gfp_kernel的标记可以引发直接的内存回收,从而导致进程阻塞睡眠,这在原子上下文显然是不允许的。
#define gfp_kernel (__gfp_reclaim | __gfp_io | __gfp_fs) #define __gfp_reclaim ((__force gfp_t)(___gfp_direct_reclaim|___gfp_kswapd_reclaim)
内存水位,pf_memalloc和gfp_atomic
那么gfp_atomic是否仅仅意味着不能睡眠呢?档案是否定的,gfp_atomic还与内存reclaim的水位相关。下面这个图是讲述水位watermark的一个著名的图,笔者懒得画了,直接从网下copy过来:
在linux中,内存有3个水位:
high: 系统的free内存大于high水位的时候,是一个相对保险的值,不需要急着做内存回收(reclaim);
low: 系统的free内存达到low水位的时候,启动后台kswapd进行内存回收,回收的目标是让空闲内存达到high水位;
min:系统应该保有的最小free内存,当空闲内存达到这个值的时候,kswapd的后台回收可能来不及了,一般用户在申请内存的时候,进行direct reclaim。
min水位一般是系统自动换算的,其具体值可以从/proc看出:
# cat /proc/sys/vm/min_free_kbytes 45056
而low水位一般是min*125%,high 一般是min*150%。
min水位以下的内存,只能被紧急情况下的用户申请到,最著名的紧急用户莫过于pf_memalloc用户,task_struct设置了这个标记表示忽略min水位。比如回收内存的代码本身也可能需要申请内存,这个时候我们应该给它无限制的申请能力。典型地,比如kswapd就设置了这个标记,这个代码里面的注释也非常精彩:
如果我们不允许回收内存的代码申请min以下的内存,则回收内存的代码可以触发回收内存,这样“子子孙孙,无穷匮也”。
当然,pf_memalloc不是唯一的紧急用户,gfp_atomic实际也是一个“半紧急”任务:
说它“紧急”,是因为如果原子上下文申请内存失败,往往意味着相应的中断、软中断、spinlock内部的代码就会执行失败,而我们又不会因为这种失败,而去尝试内存回收,这显然比较惨,我们应该尽可能让gfp_atomic申请成功;
说它“半”,是因为它不至于紧急到pf_memalloc这个程度,如果我们给它无限地申请到free内存为0的权力,则会导致pf_memalloc没有内存了。想想,如果征粮队的人都饿死了,还怎么去征粮呢?
所以,内存的设计选择是,当有人用gfp_atomic申请内存的时候,允许它从min水位以下,申请一定数量的内存。什么叫“一定数量”呢?就是不能让gfp_atomic导致free 内存触底,gfp_atomic还包含了高优先级的含义:
#define gfp_atomic (__gfp_high|__gfp_atomic|__gfp_kswapd_reclaim)
注意这个里面的__gfp_high不是highmem高端内存的意思,而是高优先级。
当我们用gfp_atomic申请内存的时候,内核的水位检查代码,会允许我们触及到min水位以下的1/2:
那么,“魔鬼”就是在画红圈的2行代码。但是,如果我们进一步深究,会发现,gfp_atomic不只是触及1/2*min,它甚至可以触及1/4*min,因为gfp_atomic中的__gfp_high让alloc_high成立,而__gfp_atomic让alloc_harder成立:
所以,“魔鬼”又隐藏在了gfp_to_alloc_flags()的细节里。
一个patch的例子
在具体的工程实战中,我们建议:
原子上下文使用gfp_atomic
比如在网络设备驱动drivers/net/ethernet中,就有大量的案例
在内存紧急的路径上(比如不想睡眠,要求低延迟;或者要求内存吃紧的情况下,仍然可以从min水位以下申请内存),哪怕是进程上下文,我们也建议可以考虑使用gfp_atomic
比如田涛童鞋最近在mm/zswap.c发的rfc patch:
https://lore.kernel.org/linux-mm/1608894171-54174-2-git-send-email-tiantao6@hisilicon.com/
上面2个地方,其实都是可以睡眠的进程上下文,但是我们认为在frontendswap的路径上,我们对延迟敏感,对swap内存过程中进一步引发内存回收也担忧,因此,这里哪怕是非原子上下文,我们也没有使用gfp_kernel。

原文标题:宋宝华:linux内核中用gfp_atomic申请内存究竟意味着什么?
文章出处:【微信公众号:linuxer】欢迎添加关注!文章转载请注明出处。

台积电表示7纳米制程领先其他同业至少一年 此外3纳米技术也已进入全面开发阶段
单相电机保养流程
无人驾驶车和现实的距离 过渡段至少持续10年之久
如何在代码中添加注释
魅族Pro7、魅族Pro7Plus最新消息汇总:魅族Pro6Plus现最低价,迎接魅族Pro7的到来
Linux内核中用GFP_ATOMIC申请内存意味着什么
!销售/收购/维修HP437B+HP8482A功率计!小兵/
中方反对以竞争为幌子打贸易战、科技战
华为畅享9Plus评测 足以成为我日常生活中的影音游戏娱乐神器
pd快充和氮化镓区别在哪
自动驾驶多千兆以太网的光学连接技术分析
台积电表示近期营运屡有杂音 但仍是最大赢家
5G时代将大幅拉动国内散热产业的增长
自动控制系统的五要素
基于TTP224的电容式触摸按键程序步骤与原理图
实用的交换机7大行业组网方案
格林美三元前驱体和四氧化三钴的全年订单订满
AcrelEMS企业微电网能效管理平台概述
碾压GPT-4!谷歌DeepMind CEO自曝:下一代大模型将与AlphaGo合体
中国制造业是嘲笑,还是时代骄傲