Linux - 内存、swap、内存回收机制

参考

2023年6月22日

2023年6月22日 qbittorrent swap 问题

正文

内存

进程内存、用户系统空间(User Space Address)、系统虚拟内存(Virtual Memory)、物理内存(Physical Memory)

程序内存 ⇒ 物理内存

  • 在linux中,程序以进程形式运行,使用的内存称为“进程内存” —— 使用
  • “进程内存”由“用户系统空间”提供 —— 资源分配、权限管理
  • “用户系统空间”由“系统虚拟内存”提供 —— 系统管理(封装硬件调用,暴露调用接口)
  • “虚拟内存”通过“内存分页”映射到“物理内存”上 —— 物理to逻辑

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

读文件

处理器直接与内存交互、不直接与硬盘交互

如果内存没预先加载想要的硬盘数据,进程会进入中断,等待硬盘数据写入内存

程序逻辑地址、内存虚拟地址、硬盘物理地址

在这里插入图片描述

进程内存

进程(progress)内存(memory)使用有两种数据结构

  • Stack(栈) —— 大小已知的小资源
    • 方法调用
    • 本地变量存储
  • Heap(堆) —— 大小可变的大资源
    • 对象存储
    • callocmallocreallocfree —— 生成/释放一定大小的“块数据(block)”

在这里插入图片描述

在“进程”的内存空间中,堆和栈的内存空间相对生长。如果两者吃满,就会导致内存用尽,抛出OOM异常,进程终止。

在这里插入图片描述
在这里插入图片描述

所以,c语言的手动内存管理(manual heap allocation)写起来麻烦,写错了更麻烦。因此,在c以后的语言或多或少用“对象(Object)”、“类(Class)”的抽象概念替代堆、栈的具体概念,有意避免下游的开发者进行手动的堆栈内存管理,然后在语言编码层面封装了内存管理流程。
在这里插入图片描述
在这里插入图片描述

当然,这种自动管理内存的模式带来的弊端是“更多的程序执行步骤”,也就是(相对)更低的程序性能。
为了提高程序性能,如希望加快Android应用的响应速度,而Java部分无法再优化时,基于C/C++开发的NDK就会被选择 —— 开发者手动管理内存。

在这里插入图片描述

swap

Linux内存管理是一套非常复杂的系统,而swap只是其中一个很小的处理逻辑。

作用

  1. 内存扩展 —— “交换分区(swap)”主要是在内存不够用的时候,将部分内存上的数据交换到swap空间上,以便让系统不会因内存不够用而导致oom或者更致命的情况出现。
  2. 内存回收 —— 当进程不再需要某些内存数据时,这些将死、无用的进程的数据可以移动到swap分区中,从而释放物理内存空间。
  3. 系统休眠、恢复 —— 当系统需要休眠时,可以将内存中的数据保存在swap分区中,以便在唤醒后可以恢复到之前的状态。

swap分区一般设置为物理内存的1.5~2倍。
实际上,更具体的考虑,应该考虑实际的物理内存大小,实际的运行程序,硬盘类型来决定swap分区大小
e.g.

  • 小内存,大swap。大内存,swap不重要,但至少要是物理内存的一倍
  • nginx吃内存小、tomcat吃内存多、文件服务器 内存决定响应速度
  • 物理硬盘,往小了设置swap分区,确保程序不oom即可。

查看(挂载)

# see MOUNTPOINT
lsblk

查看(运行时)

查看个大概

$ htop

在这里插入图片描述

查看具体数值

$ free
              total        used        free      shared  buff/cache   available
Mem:        3856724     2281072      168644        1492     1407008     1315044
Swap:       4411308     1415572     2995736

查看分区

$ swapon -s
Filename                                Type            Size    Used    Priority
/dev/md1                                partition       2097084 63360   -1
/dev/zram0                              partition       578556  334768  1
/dev/zram1                              partition       578556  335844  1
/dev/zram2                              partition       578556  334904  1
/dev/zram3                              partition       578556  335864  1

创建(文件形式)

dd if=/dev/zero of=/swapfile bs=1G count=16
chmod 0600 /swapfile
格式化
mkswap /swapfile
# 挂载
swapon /swapfile
# 验证
free -h

创建(分区形式)

mkswap /dev/sdb4
swapon /dev/sdb4
free -h

swap策略

Linux有一个内核参数vm.swappiness,取值0-100,0表示不想用swap、100表示非常想用swap

e.g. pc,16g,swappiness=60,大约在6G(16G*40%=6.4G)的内存时候开始使用swap

$ cat /proc/sys/vm/swappiness
60
$ sysctl vm.swappiness # 查看
vm.swappiness = 60
$ vm.swappiness = 60 # 临时调整
$ echo 10 > /proc/sys/vm/swappiness # 临时调整
$ cat /etc/sysctl.conf | grep swap
vm.swappiness=10
$ sysctl -p # 激活

内存回收机制

内核(kernel)进行内存回收,原因主要有两个

  1. 内核需要为突发时刻到来的“内存申请”提供足够的“内存”,所以一般情况下需要保证有足够的free空间。
    当真的有大于空闲内存的申请到来的时候,会触发强制内存回收。
  2. 内核会使用内存中的page cache对部分文件进行缓存,以便提升文件的读写效率。
    但文件读写是随机的,所以可能大部分page cache长期不会被触发。
    所以内核有要设计一个周期性回收内存的机制,避免内存被长期占用。

所以,内核在应对这两类回收的需求下,分别实现了两种不同的机制

  1. 一个是使用kswapd进程对内存进行周期检查,以保证平常状态下剩余内存尽可能够用。
  2. 一个是直接内存回收(direct page reclaim),就是当内存分配时没有空闲内存可以满足要求时,触发直接内存回收

这两种内存回收的触发路径不同:

  1. 一个是由内核进程kswapd直接调用内存回收的逻辑进行内存回收;
    参见mm/vmscan.c中的kswapd()主逻辑
  2. 一个是内存申请的时候进入slow path的内存申请逻辑进行回收。
    参见内核代码中的mm/page_alloc.c中的__alloc_pages_slowpath方法

内存回收的方法、针对的对象

内存回收的两个过程在实际进行时殊途同归,最终都是调用shrink_zone()方法进行针对每个zone的内存页缩减。

这个方法中会再调用shrink_lruvec()LRU,least recently used,最近最少使用)这个方法对每个"组织页"的链表进程检查。

这些链表主要定义在mm/vmscan.c一个enum中:

在这里插入图片描述

找到这个线索之后,我们就可以清晰的看到内存回收操作究竟针对的page有哪些了。

根据这个enum可以看到,内存回收主要需要进行扫描的链表有如下4个:

  • anoninactive
  • anonactive
  • fileinactive
  • fileactive

就是说,内存回收操作主要针对的就是内存中的文件页(file cache)和匿名页。

内存标记、内存回收流程

整个扫描的过程分几个循环:

  1. 首先扫描每个zone上的cgroup组;
  2. 然后再以cgroup的内存为单元进行page链表的扫描;
  3. 内核会先扫描anonactive链表(LRU_ACTIVE_ANON),将不频繁的放进inactive链表中(LRU_INACTIVE_ANON),然后扫描inactive链表,将里面活跃的移回active中;
    在这里插入图片描述

    关于活跃(active)还是不活跃(inactive)的判断内核会使用lru算法进行处理并进行标记,我们这里不详细解释这个过程。

  4. 进行swap的时候,先对inactive的页进行换出;
  5. 如果是file的文件映射page页(LRU_INACTIVE_FILE),则判断其是否为脏数据,如果是脏数据就写回,不是脏数据可以直接释放。

    脏数据:写入内存后,未同步

这样看来,内存回收这个行为会对两种内存的使用进行回收:

一种是anon的匿名页内存,主要回收手段是swap;

另一种是file-backed的文件映射页,主要的释放手段是写回和清空。

todo https://mp.weixin.qq.com/s?__biz=MzA4Nzg5Nzc5OA==&mid=2651660097&idx=1&sn=a3d38e3af2c9d8d431c46fe7680b428d&scene=2&srcid=0606f21oK1jm1IKMwEyi6aNz&from=timeline&isappinstalled=0#wechat_redirect

猜你喜欢

转载自blog.csdn.net/LawssssCat/article/details/131342380
今日推荐