原标题:回收和交换Linux的内存回收和交换

作者 | zorro

来自 | http://liwei.life/

微信公众号:Linux系统技术

前言

Linux的swap相关部分代码从2.6早期版本到现在的4.6版本在细节之处已经有不少变化。本文讨论的swap基于Linux 4.4内核代码。Linux内存管理是一套非常复杂的系统,而swap只是其中一个很小的处理逻辑。希望本文能让读者了解Linux对swap的使用大概是什么样子。阅读完本文,应该可以帮你解决以下问题:

swap到底是干嘛的?

swappiness到底是用来调节什么的?

什么是内存水位标记?

kswapd什么时候会进行swap操作?

swap分区的优先级(priority)有啥用?

什么是SWAP?

我们一般所说的swap,指的是一个交换分区或文件。在Linux上可以使用swapon -s命令查看当前系统上正在使用的交换空间有哪些,以及相关信息:

[zorro@zorrozou-pc0 linux-4.4]$ swapon -s

Filename Type Size Used Priority

/dev/dm-4 partition 33554428 0 -1

从功能上讲,交换分区主要是在内存不够用的时候,将部分内存上的数据交换到swap空间上,以便让系统不会因内存不够用而导致oom或者更致命的情况出现。所以,当内存使用存在压力,开始触发内存回收的行为时,就可能会使用swap空间。内核对swap的使用实际上是跟内存回收行为紧密结合的。那么内存回收和swap的关系,我们可以提出以下几个问题:

什么时候会进行内存回收呢?

哪些内存会可能被回收呢?

回收的过程中什么时候会进行交换呢?

具体怎么交换?

下面我们就从这些问题出发,一个一个进行分析。

内存回收

内核之所以要进行内存回收,主要原因有两个:

第一、内核需要为任何时刻突发到来的内存申请提供足够的内存。所以一般情况下保证有足够的free空间对于内核来说是必要的。另外,Linux内核使用cache的策略虽然是不用白不用,内核会使用内存中的page cache对部分文件进行缓存,以便提升文件的读写效率。所以内核有必要设计一个周期性回收内存的机制,以便cache的使用和其他相关内存的使用不至于让系统的剩余内存长期处于很少的状态。

第二,当真的有大于空闲内存的申请到来的时候,会触发强制内存回收。

所以,内核在应对这两类回收的需求下,分别实现了两种不同的机制。一个是使用kswapd进程对内存进行周期检查,以保证平常状态下剩余内存尽可能够用。另一个是直接内存回收(direct page reclaim),就是当内存分配时没有空闲内存可以满足要求时,触发直接内存回收。

这两种内存回收的触发路径不同,一个是由内核进程kswapd直接调用内存回收的逻辑进行内存回收(参见mm/vmscan.c中的kswapd()主逻辑),另一个是内存申请的时候进入slow path的内存申请逻辑进行回收(参见内核代码中的mm/page_alloc.c中的__alloc_pages_slowpath方法)。这两个方法中实际进行内存回收的过程殊途同归,最终都是调用shrink_zone()方法进行针对每个zone的内存页缩减。这个方法中会再调用shrink_lruvec()这个方法对每个组织页的链表进程检查。找到这个线索之后,我们就可以清晰的看到内存回收操作究竟针对的page有哪些了。这些链表主要定义在mm/vmscan.c一个enum中:

#define LRU_BASE 0

#define LRU_ACTIVE 1

#define LRU_FILE 2

enum lru_list {

LRU_INACTIVE_ANON = LRU_BASE,

LRU_ACTIVE_ANON = LRU_BASE + LRU_ACTIVE,

LRU_INACTIVE_FILE = LRU_BASE + LRU_FILE,

LRU_ACTIVE_FILE = LRU_BASE + LRU_FILE + LRU_ACTIVE,

LRU_UNEVICTABLE,

NR_LRU_LISTS

};

根据这个enum可以看到,内存回收主要需要进行扫描的包括anon的inactive和active以及file的inactive和active四个链表。就是说,内存回收操作主要针对的就是内存中的文件页(file cache)和匿名页。关于活跃(active)还是不活跃(inactive)的判断内核会使用lru算法进行处理并进行标记,我们这里不详细解释这个过程。

整个扫描的过程分几个循环,首先扫描每个zone上的cgroup组。然后再以cgroup的内存为单元进行page链表的扫描。内核会先扫描anon的active链表,将不频繁的放进inactive链表中,然后扫描inactive链表,将里面活跃的移回active中。进行swap的时候,先对inactive的页进行换出。如果是file的文件映射page页,则判断其是否为脏数据,如果是脏数据就写回,不是脏数据可以直接释放。

这样看来,内存回收这个行为会对两种内存的使用进行回收,一种是anon的匿名页内存,主要回收手段是swap,另一种是file-backed的文件映射页,主要的释放手段是写回和清空。因为针对file based的内存,没必要进行交换,其数据原本就在硬盘上,回收这部分内存只要在有脏数据时写回,并清空内存就可以了,以后有需要再从对应的文件读回来。内存对匿名页和文件缓存一共用了四条链表进行组织,回收过程主要是针对这四条链表进行扫描和操作。

swappiness的作用究竟是什么?

我们应该都知道/proc/sys/vm/swappiness这个文件,是个可以用来调整跟swap相关的参数。这个文件的默认值是60,可以的取值范围是0-100。这很容易给大家一个暗示:我是个百分比哦!那么这个文件具体到底代表什么意思呢?我们先来看一下说明:

这个文件的值用来定义内核使用swap的积极程度。值越高,内核就会越积极的使用swap,值越低就会降低对swap的使用积极性。如果这个值为0,那么内存在free和file-backed使用的页面总量小于高水位标记(high water mark)之前,不会发生交换。

在这里我们可以理解file-backed这个词的含义了,实际上就是上文所说的文件映射页的大小。那么这个swappiness到底起到了什么作用呢?我们换个思路考虑这个事情。假设让我们设计一个内存回收机制,要去考虑将一部分内存写到swap分区上,将一部分file-backed的内存写回并清空,剩余部分内存出来,我们将怎么设计?

我想应该主要考虑这样几个问题。

1.如果回收内存可以有两种途径(匿名页交换和file缓存清空),那么我应该考虑在本次回收的时候,什么情况下多进行file写回,什么情况下应该多进行swap交换。说白了就是平衡两种回收手段的使用,以达到最优。

2.如果符合交换条件的内存较长,是不是可以不用全部交换出去?比如可以交换的内存有100M,但是目前只需要50M内存,实际只要交换50M就可以了,不用把能交换的都交换出去。

分析代码会发现,Linux内核对这部分逻辑的实现代码在get_scan_count()这个方法中,这个方法被shrink_lruvec()调用。get_sacn_count()就是处理上述逻辑的,swappiness是它所需要的一个参数,这个参数实际上是指导内核在清空内存的时候,是更倾向于清空file-backed内存还是更倾向于进行匿名页的交换的。当然,这只是个倾向性,是指在两个都够用的情况下,更愿意用哪个,如果不够用了,那么该交换还是要交换。

简单看一下get_sacn_count()函数的处理部分代码,其中关于swappiness的第一个处理是:

/*

* With swappiness at 100, anonymous and file have the same priority.

* This scanning priority is essentially the inverse of IO cost.

*/

anon_prio = swappiness;

file_prio = 200 - anon_prio;

这里注释的很清楚,如果swappiness设置为100,那么匿名页和文件将用同样的优先级进行回收。很明显,使用清空文件的方式将有利于减轻内存回收时可能造成的IO压力。因为如果file-backed中的数据不是脏数据的话,那么可以不用写回,这样就没有IO发生,而一旦进行交换,就一定会造成IO。所以系统默认将swappiness的值设置为60,这样回收内存时,对file-backed的文件cache内存的清空比例会更大,内核将会更倾向于进行缓存清空而不是交换。

这里的swappiness值如果是60,那么是不是说内核回收的时候,会按照60:140的比例去做相应的swap和清空file-backed的空间呢?并不是。在做这个比例计算的时候,内核还要参考当前内存使用的其他信息。对这里具体是怎么处理感兴趣的人,可以自己详细看get_sacn_count()的实现,本文就不多解释了。我们在此要明确的概念是:swappiness的值是用来控制内存回收时,回收的匿名页更多一些还是回收的file cache更多一些。

那么swappiness设置为0的话,是不是内核就根本不会进行swap了呢?这个答案也是否定的。首先是内存真的不够用的时候,该swap的话还是要swap。其次在内核中还有一个逻辑会导致直接使用swap,内核代码是这样处理的:

/*

* Prevent the reclaimer from falling into the cache trap: as

* cache pages start out inactive, every cache fault will tip

* the scan balance towards the file LRU. And as the file LRU

* shrinks, so does the window for rotation from references.

* This means we have a runaway feedback loop where a tiny

* thrashing file LRU becomes infinitely more attractive than

* anon pages. Try to detect this based on file LRU size.

*/

if (global_reclaim(sc)) {

unsigned long zonefile;

unsigned long zonefree;

zonefree = zone_page_state(zone, NR_FREE_PAGES);

zonefile = zone_page_state(zone, NR_ACTIVE_FILE) +

zone_page_state(zone, NR_INACTIVE_FILE);

if (unlikely(zonefile + zonefree <= high_wmark_pages(zone))) {

scan_balance = SCAN_ANON;

goto out;

}

}

这里的逻辑是说,如果触发的是全局回收,并且zonefile + zonefree <= high_wmark_pages(zone)条件成立时,就将scan_balance这个标记置为SCAN_ANON。后续处理scan_balance的时候,如果它的值是SCAN_ANON,则一定会进行针对匿名页的swap操作。要理解这个行为,我们首先要搞清楚什么是高水位标记(high_wmark_pages)。

xià rì zhī gē

♫. ♪~♬..♩

往期回顾

关于夏天的诗

END

1

责任编辑:

linux内存回收500M,回收和交换Linux的内存回收和交换相关推荐

  1. linux内存管理笔记(三十九)----kswapd内存回收

    在linux操作系统中,当内存充足的时候,内核会尽量使用内存作为文件缓存(page cache),从而提高系统的性能.例如page cache缓冲硬盘中的内容,dcache.icache缓存文件系统的 ...

  2. Linux内存管理(三十九):页面回收简介和 kswapd详解(1)

    源码基于:Linux5.4 0. 前言 在 LRU简介 一文和 LRU 第二次机会法 一文中,提到当内存出现紧张的时候,会将 inactive list 尾部的 page 进行换出,从而将page 释 ...

  3. Linux多线程编程:pthread线程创建、退出、回收、分离、取消

    文章目录 Linux线程 1.简单了解一下线程 2.线程创建:pthread_create 3.线程传参注意事项 4.线程退出:pthread_exit 5.线程回收:pthread_join 6.线 ...

  4. linux umount swap,挂载、卸载、free查看内存情况、创建交换分区、回环设备、dd命令、自动挂载、fuser...

    挂载.卸载 分区.格式化创建了文件系统后就可以挂载了 挂载:将新的文件系统关联至当前根文件系统 卸载:将某文件系统与当前根文件系统的关联关系移除 mount挂载 使用方法: mount 设备 挂载点 ...

  5. linux内核中的文件描述符(三)--fd的回收

    linux内核中的文件描述符(三)--fd的回收 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csd ...

  6. linux free命令详解和使用实例(查看内存使用率)

    free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存,及被内核使用的buffer.在Linux系统监控的工具中,free命令是最经常使用的命令之一 1.命令格式: free [参数 ...

  7. 检测linux服务器的使用情况,如何在Linux服务器中检查内存使用情况

    我们在排除服务器系统或应用程序速度减慢或行为不正常的问题时,首先要检查的是系统内存使用情况. 本文介绍了如何在Linux系统服务器中使用几个不同的命令来检查RAM的使用情况. 1.free命令 fre ...

  8. linux内存管理的主要概念是虚拟内存,有关linux内存管理机制的相关内容,linux物理内存和虚拟内存,深入了解Linux内存运行 ......

    在linux中空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然. 这是Linux内存管理的一个优秀特性,区别于Windows的内存管理. 主要特点: 无论物理内存有多大,L ...

  9. linux 内存管理_真香!Linux 原来是这么管理内存的

    这是 Linux 系列第三篇文章,前两篇文章如下 程序员cxuan:初识 Linux 系统,就这一篇了!​zhuanlan.zhihu.com 程序员cxuan:Linux 进程必知必会​zhuanl ...

  10. linux进程间通信快速入门【二】:共享内存编程(mmap、XSI、POSIX)

    文章目录 mmap内存共享映射 XSI共享内存 POSIX共享内存 参考 使用文件或管道进行进程间通信会有很多局限性,比如效率问题以及数据处理使用文件描述符而不如内存地址访问方便,于是多个进程以共享内 ...

最新文章

  1. COM如何区分套间线程(apartment thread)和自由线程(free thread)
  2. 比特现金网络升级之争:1个CPU=1票
  3. 带android小绿人的屏保相册,盘点:那些年我们追过的Android
  4. CVPR 2019 | 告别低分辨率网络,微软提出高分辨率深度神经网络HRNet
  5. 二甲医院云服务器,医院用上云计算 病情上传到云端可行否?
  6. Densenet论文解读 深度学习领域论文分析博主
  7. springboot项目发布到独立的tomcat中运行
  8. 英世曼 | 动量是否具有行为性?
  9. 域名IP段批量生成器源码
  10. 有线猫眼监控_如何安装有线监控摄像头系统
  11. STM32的内存扩展应用实现,小内存的单片机也能干大事(FSMC+SRAM)
  12. android(6.0,11.0)开启wifi热点
  13. Hbuilder屏幕旋转
  14. 计算机组成原理笔记(王道考研) 第二章:数据的表示和运算2
  15. python处理数据
  16. 如何使用IP摄像头进行电脑直播
  17. java 排班日历,排班考勤表的制作也很简单,赶快来试试吧
  18. html调色盘字符,油画基础知识:调色盘最详细讲解
  19. 企微和钉钉发力,送谁一首《凉凉》?
  20. 跟西乔一起开脑洞,预测AIGC的终极形态

热门文章

  1. vue : 无法加载文件 D:\Program Files\nodejs\vue.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsof t.com/fwlin
  2. matlab如何获得一个二值掩码,1.3矩阵的掩码操作 - osc_uarhdl2n的个人空间 - OSCHINA - 中文开源技术交流社区...
  3. linux 环境变量_linux的环境变量
  4. android 手机头提示消息,正确的手机头部声明(android,iphone)
  5. 树莓派串口通信编码_树莓派和STM32通过USB和串口通信记录
  6. 微课有关计算机应用基础,【计算机仿真论文】微课在计算机应用基础课的应用(共3802字)...
  7. php 判断邮箱_php检测邮箱地址是否存在
  8. nuget的原理_从零开始学习 dotnet 编译过程和 Roslyn 源码分析
  9. java 判断 and_Java中如何判断两个对象是否相等(Java equals and ==)
  10. java比较两个对象_Java比较两个对象