前言
先来看下本机系统显存使用情况:数值默认单位为 KB
# 笔记本本机 16G 内存,Ubuntu 18
$ free
total used free shared buff/cache available
Mem: 16306984 13655780 1205560 576992 1445644 1748628
Swap: 2097148 1620224 476924
# -h 适配可读的单位。-m 即 MB 为单位
$ free -h
total used free shared buff/cache available
Mem: 15G 13G 320M 649M 1.6G 1.0G
Swap: 2.0G 1.6G 435M
关于Buff/Cache,可以通过man free指南来查看说明:
由上,并结合平常开发经验,推测显存组成部份:堆内存、堆外显存、Page Cache、其他
问题:在 64位系统下,虚拟地址空间中 内核空间 和 用户空间 均占 128T,可对应的空间在物理内存中占多少?
这似乎没有一个明晰的答案北京linux培训,因为 内核空间 和 用户空间 共享同一个物理内存。 但我们平常开发时(Kafka、ES)经常接触到 Page Cache,同时希望能分配更多显存给 Page Cache。 要么限制 Page Cache 的大小,要么限制应用程序的大小。 一般我们都选择限制应用程序,举个栗子: 安装 ES 在 8C16G 机子下,设置最大和最小堆显存为 8G,-Xms8g -Xmx8g。目的就是留一半显存给 Page Cache。
下面注重来介绍 Page Cache 与 Swap。
Page Cache 页缓存
Page cache:也叫页缓冲 或 文件缓冲,也叫 ES 中的 filesystem cache。
问题:为什么须要Page Cache?
举个栗子:写文件
调用 write(2)函数,写入 Page Cache后就返回,内核会手动刷盘(把 Page Cache 中数据写入c盘)。
来看张神图,应用程序形成 Page Cache 的逻辑示意图:
从图中可知:
Page Cache是内核管理的显存,属于内核不属于用户。有两种形式可以形成 Page Cache:标准I/O(Buffered I/O) 和 MMAP(Memory-Mapped I/O)Linux I/O 有 3 种形式:标准I/O、MMAP 和 Direct I/O
要剖析此图,我们还须要先了解 Linux IO 栈:
虚拟文件系统(VFS) :对各类文件系统的一个具象,它为各类文件系统提供了一个通用的插口。块层(Block I/O) :管理块设备的 IO 队列,对 IO 请求进行合并、排序。设备驱动(Device Driver) :操作储存介质。
再看 Linux I/O 3 种形式,这里做了简化:
问题:为什么上张图里有VFS,这图改为File System文件系统?回答:VFS 就像插口,定义好插口,其他人就来实现就行。File System文件系统更为具体化。举个栗子:open() 函数,可以以特定的文件描述符打开某一个文件。使用:fd = open("myfile", O_RDWR | O_CREAT | O_SYNC | O_DIRECT, S_IRUSR | S_IWUSR);
这里注重再介绍下 Direct I/O: 是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件。
想要实现直接 I/O,需要在系统调用中,指定 O_DIRECT 标识。
官方文档
官方文档中的说明,主要彰显了 3 点:
缺点: 这种方法会增加性能。(磁盘读写、磁盘寻道等。)特殊应用场景: 应用程序自己管理缓存,文件I/O直接对接用户空间缓冲区。(对开发者能力要求高)不保证同步: 不能确保每次写入都同步数据到c盘,还是须要设置 O_SYNC 标识或则自动 fsync。
Tips:Java基本库不支持Direct I/O,若想使用需引入JNA包。
Swap 交换区
Swap 说白了就是把一块c盘空间或则一个本地文件(以下讲解以c盘为例),当成显存来使用。
Swap 把这种不常访问的显存先写到c盘中,然后释放那些显存,给其他更需要的进程使用。再次访问那些显存时linux swap空间释放,重新从c盘读入显存就可以了。
问题:为什么一些中间件都建议关掉Swap?
性能问题: 例如 ES,与 JVM 的 GC 相关。GC会遍历所用到的堆的显存,如果有部门显存被 Swap 到c盘,那么 GC 遍历时侯才会去查c盘arm linux,磁盘 IO 又很慢,这都会造成应用程序 STW 假死一段时间。
ES文档
管理问题: 例如 K8slinux swap空间释放,开启 Swap后通过 Cgroups 设置的显存上限都会失效。