细节篇(8):RSS和Page Cache

在一些场景中,比如容器里的应用有很多文件读写,整个容器的内存使用量已经很接近 Memory Cgroup 的上限值了,但接着申请内存,还是可以申请出来,并且没有 OOM。

Linux 内存类型

Linux 的各个模块都需要内存,比如内核需要分配内存给页表,内核栈,还有 slab,也就是内核各种数据结构的 Cache Pool;用户态进程里的堆内存和栈的内存,共享库的内存,还有文件读写的 Page Cache。

Memory Cgroup 不会对内核的内存做限制。主要讨论与用户态相关的两个内存类型,RSS 和 Page Cache。

RSS

RSS 是 Resident Set Size 的缩写,指进程真正申请到物理页面的内存大小。

程序在申请内存时,比如调用 malloc() 申请 100MB 的内存,返回成功,系统其实只是把 100MB 的虚拟地址空间分配给了进程,没有分配物理内存。当进程对内存地址开始做真正读写时,系统才把实际需要的物理内存分配给进程。这个过程中,进程真正得到的物理内存,就是 RSS。

用 malloc 申请 100MB 的内存。

运行 top 查看程序在运行了 malloc() 之后的内存,程序的虚拟地址空间(VIRT)已经有了 106728KB(~100MB),但是实际的物理内存 RSS(top 里显示的是 RES)在这里只有 688KB。

等待30s,再对申请的内存写入20MB数据

用 memset() 对地址空间写入 20MB 的数据后,再用 top 查看

对于进程来说,RSS 内存包含了进程的代码段内存,栈内存,堆内存,共享库的内存。刚才通过 malloc/memset 得到的内存,就属于堆内存。

具体的每一部分的 RSS 内存的大小,可以查看 /proc/[pid]/smaps 文件。

Page Cache

进程除了分配到的 RSS 内存外,如果对磁盘上的文件做了读写操作,Linux 还会分配内存,把磁盘上读写到的页面存放在内存中,这部分的内存就是 Page Cache。

Page Cache 的主要作用是提高磁盘文件的读写性能,因为系统调用 read() 和 write() 的default行为都会把读过或者写过的页面存放在 Page Cache 里。

在 Linux 里只要有空闲的内存,系统就会自动地把读写过的磁盘文件页面放入到 Page Cache 里。但执行 malloc()时,剩余的物理内存不够了,那该怎么办呢?

Linux 的内存管理有一种内存页面回收机制,会根据系统里空闲物理内存是否低于某个阈值,来决定是否启动内存的回收。

内存回收的算法会根据不同类型的内存以及 LRU 算法决定哪些内存页面先被释放。因为 Page Cache 的内存页面只是起到 Cache 作用,自然是会被优先释放的。

所以,Page Cache 是一种为了提高磁盘文件读写性能而利用空闲物理内存的机制。页面回收机制又能保证 Cache 所占用的页面可以及时释放,这样就不会影响程序对内存的真正需求了。

RSS & Page Cache in Memory Cgroup

先从 Linux 的内核代码看一下,从 mem_cgroup_charge_statistics() 这个函数里,可以看到 Memory Cgroup 只统计了 RSS 和 Page Cache 这两部分的内存。

Memory Cgroup 控制组里 RSS 内存和 Page Cache 内存的和,正好是 memory.usage_in_bytes 的值。

当控制组里的进程需要申请新的物理内存,而且 memory.usage_in_bytes 里的值超过控制组里的内存上限,这时 Linux 的内存回收就会被调用。

控制组里的 page cache 的内存会根据新申请的内存大小释放一部分

相关推荐
阿尔帕兹2 小时前
构建 HTTP 服务端与 Docker 镜像:从开发到测试
网络协议·http·docker
ZHOU西口3 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac
景天科技苑6 小时前
【云原生开发】K8S多集群资源管理平台架构设计
云原生·容器·kubernetes·k8s·云原生开发·k8s管理系统
wclass-zhengge7 小时前
K8S篇(基本介绍)
云原生·容器·kubernetes
颜淡慕潇7 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
川石课堂软件测试9 小时前
性能测试|docker容器下搭建JMeter+Grafana+Influxdb监控可视化平台
运维·javascript·深度学习·jmeter·docker·容器·grafana
昌sit!15 小时前
K8S node节点没有相应的pod镜像运行故障处理办法
云原生·容器·kubernetes
追风林16 小时前
mac 本地docker-mysql主从复制部署
mysql·macos·docker
A ?Charis18 小时前
Gitlab-runner running on Kubernetes - hostAliases
容器·kubernetes·gitlab
城南vision18 小时前
Docker学习—Docker核心概念总结
java·学习·docker