1. page cache
Linux 读写文件过程;
read: 用户进程调用 read 命令,内核查询读取的文件内容是否在内存 (内核 page cache) 中,若该页内容缓存在内存中,直接读取返回给用户进程;若缓存不存在,则启动 BIO,从硬盘读取该页面到内存,再送给用户进程;
write过程:比如往某文件 5K 处写入 10byte,内核先查询该页是否在内存缓存(内核 page cache),不在,同 read, 从硬盘读取该页 4\~8K 到内存,再往 5k 处写入 10byte, 标明该页为脏页;
写回磁盘时机,则由内存管理的 BIO 机制决定。
Linux 读写文件两种方式:read/write,mmap
相同点:都经过 page cache 中介操作磁盘文件;
区别:
read/write:有一个用户空间和内核空间的拷贝过程;
mmap:指针直接操作文件映射的虚拟地址,省略了用户空间和内核空间的拷贝过程。
缺点是,很多设备不支持 mmap,比如串口,键盘等都不支持。
2.free 命令的详细解释
total: 系统总的内存
第一行 used: 所有用掉的内存,包括 app,kernel,page cached(可回收);
第一行 free: =total-used
第一行 buffers/cached:page cached 内存
第二行 free = 第一行 free+buffers+cached
114380=31040+8988+74352
第二行 used = 第一行 used-buffers-cached
40072=123412-8988-74352
第一行 used 是从 buddy 的角度,统计所有用掉的内存(包括 page cached);
第二行 uesed,是从进程角度,包括 app/kernel/ , 不含 page cached(可回收)。
cached/buffer 区别:
cached: 通过文件系统访问;
buffer: 裸地址直接访问,存放文件系统的元数据(组织数据的数据);
新版 free,去掉了 buffer/cached 的区别,加入一个 available,预估可用内存
在 cat /proc/meminfo 也可以看到预估项 MemAvailable
查看实现方法 git grep MemAvailable
vim fs/proc/meminfo.c
搜 MemAvailable,实现函数 si_mem_available
git grep si_mem_available
vim mmpage_alloc.c-- >long si_mem_available(void)
3.read、write 和 mmap
mmap 映射文件过程,实际上在进程创建一个 vma,映射到文件,当真正读 / 写文件时,分配内存,同步磁盘文件内存。
其本质是虚拟地址映射到 page cached, page cached 再跟文件系统对应。
这里的 page cached 是可以回收的。
4.file-backed 的页面和匿名页
在一个 elf 文件中,代码段的本质,就是对应 page cached;
真正执行到的代码,才会从磁盘读入内存,并且还可能被踢走,下次再执行,可能需要重新从磁盘读取。
Reclaim 可回收的
有文件背景的页面,叫 file-back page, 可回收
** 匿名页:anon,不可回收,常驻内存;
pmap pid
Anon: stack、heap、CoW pages
File-backed:代码段,映射文件,可回收。
5.swap 以及 zRAM
案例,当同时运行 word 和 qq,word 需要 400M 匿名页,qq 需要 300M 匿名页,而物理内存只有 512M,如何运行呢,此时伪造一个可 swap 的文件,供 anon 匿名页交换。
在内核配置 CONFIG_SWAP,支持匿名页 swap,不配置,普通文件 swap 依然支持;
SWAP 分区,对应 windows 的虚拟内存文件 pagefile.system。
6. 页面回收和 LRU
局部性原理:最近活跃的就是将来活跃的,最近不活跃的,以后也不活跃。
包括时间局部性,空间局部性。
LRU:Least Recently Used 最近最少使用,是一种常用的页面置换算法,
真实统计过程,无关进程,只统计页面的活跃度;
案例,开启浏览器 chrome;长期不使用,运行 oom.c 消耗掉系统所有内存,再去第一次打开网页时,速度会很慢,因为需要重新加载被踢出去的不活跃页面。
**sudo swapoff –a**
**echo 1 > /proc/sys/vm/overcommit_memory**
**cat /proc/pid/smps >1**
**./oom.out**
**cat /proc/pid/smaps >2**
**meld 1 2**
可见命中的部分 page cached,被 LRU 踢走。
CPU>>mm>>io
嵌入式设备,一般不用 swap,不使能 swap,因为:
1. 嵌入式磁盘速度很慢;
2.FLASH 读写寿命有限;
zRAM
在物理内存划分一部分,作为“swap”分区,用来做页面回收置换,利用强大 CPU 算力换取更大内存空间;
内核使能 swap
echo $((48*1024*1024)) > /sys/block/zram0/disksize
打开 swap 分区:
swapon –p 10 /dev/zram0
cat /proc/swaps
swapoff –a 不能关掉文件背景页面。
不带 pagecached 的 IO,direct IO。在用户态根据业务特点做 cached.
类似于 CPU 跳过 cache,直接访问 mem;