作者 | 宋宝华  责编 | 张文

头图 | CSDN 下载自东方 IC

来源 | Linux阅码场(ID:LinuxDev)

本文目的:本文补充校正一些 Linux 内核开发者关于 GFP_ATOMIC 的认知不完整的地方,阐述 GFP_ATOMIC 与 free 内存 watermark 的关系,并明确什么时候应该用 GFP_ATOMIC 申请内存。

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 的一个著名的图。

在 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。

更多精彩推荐
☞程序员求生指南:告别大小周,摆脱监视,直奔年终奖!
☞涉违法!「健康码演示」APP 已下架☞“火星人”马斯克推论:世界或是被编码而成,上帝可能是个程序员!
☞他曾一举击败英伟达,却因坚持研发背负骂名☞教育行业 A 股 IPO 第一股,如何做成程序员培训这门生意 | 极客头条☞13 年 29 款手机,从激进到求稳,iPhone 都经历什么?
☞45 年编程经验告诉我的技术真相
点分享点收藏点点赞点在看

Linux 内核中用 GFP_ATOMIC 申请内存究竟意味着什么?相关推荐

  1. 宋宝华:Linux内核中用GFP_ATOMIC申请内存究竟意味着什么?

    本文目的 本文补充校正一些Linux内核开发者关于GFP_ATOMIC的认知不完整的地方,阐述GFP_ATOMIC与free内存watermark的关系,并明确什么时候应该用GFP_ATOMIC申请内 ...

  2. Linux内核源代码情景分析-内存管理

    用户空间的页面有下面几种: 1.普通的用户空间页面,包括进程的代码段.数据段.堆栈段.以及动态分配的"存储堆". 2.通过系统调用mmap()映射到用户空间的已打开文件的内容. 3 ...

  3. Linux内核之浅谈内存寻址

    Linux内核之浅谈内存寻址 前言 最近在看内存寻址的内容,略有所得,发此文与大家一起交流.我们知道计算机是由硬件和软件组成,硬件主要包括运算器.控制器.存储器.输入设备和输出设备,软件主要是操作系统 ...

  4. 阅读 Linux 内核源码——共享内存

    介绍 我看的是linux-4.2.3的源码.参考了<边干边学--Linux内核指导>(鬼畜的书名)第16章内容,他们用的是2.6.15的内核源码. 现在linux中可以使用共享内存的方式有 ...

  5. Linux内核最新的连续内存分配器(CMA)——避免预留大块内存【转】

    转自:https://blog.csdn.net/21cnbao/article/details/7309757 在我们使用ARM等嵌入式Linux系统的时候,一个头疼的问题是GPU,Camera,H ...

  6. Linux内核最新的连续内存分配器(CMA)——避免预留大块内存

    By LiAnLab.org/宋宝华 在我们使用ARM等嵌入式Linux系统的时候,一个头疼的问题是GPU,Camera,HDMI等都需要预留大量连续内存,这部分内存平时不用, 但是一般的做法又必须先 ...

  7. 一文讲解,Linux内核——Memory Barrier(内存屏障)

    本文例子均在 Linux(g++)下验证通过,CPU 为 X86-64 处理器架构.所有罗列的 Linux 内核代码也均在(或只在)X86-64 下有效. 本文首先通过范例(以及内核代码)来解释 Me ...

  8. 【Linux内核】kmalloc分配内存大小(非常详细)

    文章目录 1. kmalloc分配内存的大小 1.1. KMALLOC_MAX_SIZE:kmalloc可以分配的最大内存 1.2. KMALLOC_MAX_CACHE_SIZE:kmalloc使用s ...

  9. 【Linux 内核】Linux 内核体系架构 ( 进程调度 | 内存管理 | 中断管理 | 设备管理 | 文件系统 )

    文章目录 一.进程调度 二.内存管理 三.中断管理 四.设备管理 五.文件系统 一.进程调度 进程调度 : 进程 是 系统中 进行 资源分配 的 基本单位 ; 每个进程 在 运行时 , 都 感觉自己占 ...

最新文章

  1. 2022-2028年中国内衣用热熔胶膜行业发展现状调查及市场分析预测报告
  2. Windows server backup笔记 WSB
  3. Windows 快速删除 大量文件
  4. java调用接口失败重试,httpclient接口测试中重试控制器设置
  5. 程序的加载和执行(五)——《x86汇编语言:从实模式到保护模式》读书笔记25
  6. 一篇博客读懂设计模式之---模板方法模式
  7. quick-cocos2d-x for mac开发环境安装配置
  8. 小米平板位置服务器,小米平板 2
  9. Java题目筛选器_【024期】JavaWeb面试题(五):Filter和Listener
  10. C语言:从键盘输入一个正整数,将该数倒序输出。
  11. 小D课堂 - 新版本微服务springcloud+Docker教程_5-04 feign结合hystrix断路器开发实战下...
  12. linux shell sort多字段排序
  13. 两边放动物对战守城的游戏_疯狂动物园小程序游戏:入口
  14. 计算机考研408-2010
  15. fortran程序设计2011年注册电气工程师基础考试大纲3
  16. 微信小程序video自定义播放与暂停按钮
  17. 3Dmark2006真让人郁闷!
  18. 交互式电子白板android,交互式电子白板_触摸屏电子白板_智能电子白板_GESEE国视科技...
  19. 以儒始,以道终:九十年代新武侠电影观
  20. 钉钉添加自定义机器人,实现每周定时@某人

热门文章

  1. Git Pull Failed:Could not read from remote repository
  2. 【软件工程】--软工文档总结
  3. 【机房收费系统】---组合查询
  4. J2EE的13种核心技术简介
  5. 求100~200间的所有素数
  6. 暴力推荐2:硬盘分区丢失之DiskGenius
  7. windows 下opencv for python 的安装
  8. ios app开发简单实例--源代码管理的基本操作
  9. 传统的主从复制的概念和要点
  10. fastscript传递参数