参考
2023年6月22日
- https://zhuanlan.zhihu.com/p/107350459 —— 讨论的swap基于Linux4.4内核代码
- 内存深度科普: 从堆内存到虚拟内存管理
2023年6月22日 qbittorrent swap 问题
- https://github.com/qbittorrent/qBittorrent/issues/12947
massif
valgrind --tool=massif qbittorrent
- https://github.com/qbittorrent/qBittorrent/issues/12326#issuecomment-606296172
MTTuner
- https://github.com/qbittorrent/qBittorrent/issues/12326#issuecomment-606296172
- https://github.com/qbittorrent/qBittorrent/issues/11372
正文
内存
进程内存、用户系统空间(User Space Address)、系统虚拟内存(Virtual Memory)、物理内存(Physical Memory)
程序内存 ⇒ 物理内存
- 在linux中,程序以进程形式运行,使用的内存称为“进程内存” —— 使用
- “进程内存”由“用户系统空间”提供 —— 资源分配、权限管理
- “用户系统空间”由“系统虚拟内存”提供 —— 系统管理(封装硬件调用,暴露调用接口)
- “虚拟内存”通过“内存分页”映射到“物理内存”上 —— 物理to逻辑
读文件
处理器直接与内存交互、不直接与硬盘交互
如果内存没预先加载想要的硬盘数据,进程会进入中断,等待硬盘数据写入内存
程序逻辑地址、内存虚拟地址、硬盘物理地址
进程内存
进程(progress)内存(memory)使用有两种数据结构
- Stack(栈) —— 大小已知的小资源
- 方法调用
- 本地变量存储
- Heap(堆) —— 大小可变的大资源
- 对象存储
calloc
、malloc
、realloc
、free
—— 生成/释放一定大小的“块数据(block)”
在“进程”的内存空间中,堆和栈的内存空间相对生长。如果两者吃满,就会导致内存用尽,抛出OOM
异常,进程终止。
所以,c语言的手动内存管理(
manual heap allocation
)写起来麻烦,写错了更麻烦。因此,在c
以后的语言或多或少用“对象(Object)”、“类(Class)”的抽象概念替代堆、栈的具体概念,有意避免下游的开发者进行手动的堆栈内存管理,然后在语言编码层面封装了内存管理流程。
当然,这种自动管理内存的模式带来的弊端是“更多的程序执行步骤”,也就是(相对)更低的程序性能。
为了提高程序性能,如希望加快Android应用的响应速度,而Java部分无法再优化时,基于C/C++开发的NDK就会被选择 —— 开发者手动管理内存。
swap
Linux内存管理是一套非常复杂的系统,而swap只是其中一个很小的处理逻辑。
作用
- 内存扩展 —— “交换分区(swap)”主要是在内存不够用的时候,将部分内存上的数据交换到swap空间上,以便让系统不会因内存不够用而导致oom或者更致命的情况出现。
- 内存回收 —— 当进程不再需要某些内存数据时,这些将死、无用的进程的数据可以移动到swap分区中,从而释放物理内存空间。
- 系统休眠、恢复 —— 当系统需要休眠时,可以将内存中的数据保存在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
)进行内存回收,原因主要有两个:
- 内核需要为突发时刻到来的“内存申请”提供足够的“内存”,所以一般情况下需要保证有足够的
free
空间。
当真的有大于空闲内存的申请到来的时候,会触发强制内存回收。 - 内核会使用内存中的
page cache
对部分文件进行缓存,以便提升文件的读写效率。
但文件读写是随机的,所以可能大部分page cache
长期不会被触发。
所以内核有要设计一个周期性回收内存的机制,避免内存被长期占用。
所以,内核在应对这两类回收的需求下,分别实现了两种不同的机制:
- 一个是使用
kswapd
进程对内存进行周期检查,以保证平常状态下剩余内存尽可能够用。 - 一个是直接内存回收(
direct page reclaim
),就是当内存分配时没有空闲内存可以满足要求时,触发直接内存回收。
这两种内存回收的触发路径不同:
- 一个是由内核进程
kswapd
直接调用内存回收的逻辑进行内存回收;
参见mm/vmscan.c
中的kswapd()
主逻辑 - 一个是内存申请的时候进入
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个:
anon
的inactive
anon
的active
file
的inactive
file
的active
就是说,内存回收操作主要针对的就是内存中的文件页(file cache)和匿名页。
内存标记、内存回收流程
整个扫描的过程分几个循环:
- 首先扫描每个
zone
上的cgroup
组; - 然后再以
cgroup
的内存为单元进行page
链表的扫描; - 内核会先扫描
anon
的active
链表(LRU_ACTIVE_ANON
),将不频繁的放进inactive
链表中(LRU_INACTIVE_ANON
),然后扫描inactive
链表,将里面活跃的移回active
中;
关于活跃(active)还是不活跃(inactive)的判断内核会使用lru算法进行处理并进行标记,我们这里不详细解释这个过程。
- 进行
swap
的时候,先对inactive
的页进行换出; - 如果是
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