2-PageCachechan产生释放及优化( 二 )


第二种,直接使用I/O(直接读写) 来绕过 Page Cache,不使用 Cache 了
下面举例为什么需要
标准 I/O 和内存映射会先把数据写入到 ,这样做会通过减少 I/O 次数来提升读写效率 。我们看一个具体的例子 。首先,我们来生成一个 1G 大小的新文件,然后把 Page Cache 清空,确保文件内容不在内存中, 以此来比较第一次读文件和第二次读文件耗时的差异 。具体的流程如下
先成一个 1G 的文件:
ddif = /dev/zeroof = /home/yafang/test/dd.outbs = 4096count =((1024*256))
其次,清空 Page Cache,需要先执行一下 sync 来将脏页(第二节课,我会解释一下什么是脏页)同步到磁盘再去 drop cache
$ sync && echo 3 > /proc/sys/vm/drop_caches
第一次读取文件的耗时如下:
$ time cat /home/yafang/test/dd.out &> /dev/nullreal 0m5.733suser 0m0.003ssys 0m0.213s
再次读取文件的耗时如下:
$ time cat /home/yafang/test/dd.out &> /dev/nullreal 0m0.132suser 0m0.001ssys 0m0.130s
通过这样详细的过程你可以看到,第二次读取文件的耗时远小于第一次的耗时,这是因为第一次是从磁盘来读取的内容,磁盘 I/O 是比较耗时的,而第二次读取的时候由于文件内 容已经在第一次读取时被读到内存了,所以是直接从内存读取的数据,内存相比磁盘速度是快很多的 。这就是 Page Cache 存在的意义:减少 I/O,提升应用的 I/O 速度 。
不足的地方是 它对应用程序太过于透明,以至于应用程序很难有好方法来控制它
的产生和释放 的产生
Page Cache 的产生有两种不同的方式:
I/O(标准 I/O);
- I/O(存储映射 I/O):
这两种方式分别都是如何产生 Page Cache 的呢?来看下面这张图:
'
? 产生示意图
虽然二者都能产生 Page Cache,但是二者的还是有些差异的:
*标准 I/O *是写的 (write(2)) 用户缓冲区 ( Page 对应的内存),然后再将用户缓冲区里的数据拷贝到内核缓冲区 ( Page 对应的内存);
如果是读的 (read(2)) 话则是先从内核缓冲区拷贝到用户缓冲区,再从用户缓冲区读数据,也就是和文件内容 不存在任何映射关系 。
对于*存储映射 I/O *而言,则是直接将Page 给映射到用户地址空间,用户直接读写Page 中内容
存储映射 I/O 要比标准 I/O 效率高一些,毕竟少了“用户空间到内核空间互相拷贝”的过程 。这也是很多应用开发者发现,为什么使用内存映射 I/O 比标准 I/O 方式性能要好一些的主要原因 。
脚本演示标准 I/O 产生的过程 。
#!/bin/sh#这是我们用来解析的文件MEM_FILE="/proc/meminfo"#这是在该脚本中将要生成的一个新文件NEW_FILE="/home/yafang/dd.write.out"#我们用来解析的Page Cache的具体项active=0inactive=0pagecache=0IFS=' '#从/proc/meminfo中读取File Page Cache的大小function get_filecache_size(){items=0while read linedoif [[ "$line" =~ "Active:" ]]; thenread -ra ADDR <<<"$line"active=${ADDR[1]}let "items=$items+1"elif [[ "$line" =~ "Inactive:" ]]; thenread -ra ADDR <<<"$line"inactive=${ADDR[1]}let "items=$items+1"fiif [ $items -eq 2 ]; thenbreak;fidone < $MEM_FILE} #读取File Page Cache的初始大小get_filecache_sizelet filecache="$active + $inactive"#写一个新文件,该文件的大小为1048576 KBdd if=/dev/zero of=$NEW_FILE bs=1024 count=1048576 &> /dev/null#文件写完后,再次读取File Page Cache的大小get_filecache_size#两次的差异可以近似为该新文件内容对应的File Page Cache#之所以用近似是因为在运行的过程中也可能会有其他Page Cache产生let size_increased="$active + $inactive - $filecache"#输出结果echo "File size 1048576KB, File Cache increased" $size inc