linux拷贝数据时buffer很高,Linux buffer/cache 内存占用过高的原因以及解决办法

表现现象

在Linux系统中,我们经常用free命令来查看系统内存的使用状态。在一个 CoreOS 的系统上,free命令的显示内容大概是这样一个状态:

core@localhost ~ $ free

total used free shared buff/cache available

Mem: 8145320 391200 333888 204616 7420232 311660

Swap: 0 0 0

这里的默认显示单位是kb,我们可以通过添加-h参数,来让free 命令显示的更为友好一些。

core@localhost ~ $ free -h

total used free shared buff/cache available

Mem: 7.8Gi 381Mi 0.3Gi 199Mi 7.4Gi 0.3Gi

Swap: 0B 0B 0B

新版linux相对来说已经好很多了,在老版的时候,是没有available字段的。

所以放当时来说,大家可能会有下面几种反应:

对于不太了解linux系统的人来说,看到 free 之后,会觉得内存用了好多,我都没跑什么程序,内存就用完了!Linux好占内存!

稍微了解linux,并在百度搜索过相关知识的人也许会说,嗯,看起来free是没有多少了,但是真实内存才用了 400Mi 不到,还有很多剩余内存可用。buff/cache 占用比较多,说明系统中有进程曾经读写过文件,但是不要紧,这部分内存在系统内存吃紧的时候会释放出来的。

但是,上面两种说法都有些片面了,都不是很正确。接下来让我们重新来认识一下buff和cache。

什么是 buff/cache?

在Linux 2.4的内存管理中,buffer指Linux内存的:Buffer cache。cache指Linux内存中的:Page cache。一般呢,是这么解释两者的。

A buffer is someting that has yet to be ‘written’ to disk.

A cache is someting that has been ‘read’ from the disk and stored for later use.

翻译过来就是说:

buffer(buff) 是用来缓存尚未“写入”磁盘的内容。

cache 是用来缓存从磁盘“读取”出来的东西。

所以 buffer 被用来当成对io设备写的缓存。而 cache 被用来当作对io设备的读缓存。这里的io设备,主要指的是块设备文件和文件系统上的普通文件。

但是在 Linux 2.6 以后,它们的意义不一样了。

在Linux 2.6之后Linux将他们统一合并到了Page cache作为文件层的缓存。而buffer则被用作block层的缓存。

block层的缓存是什么意思呢,你可以认为一个buffer是一个physical disk block在内存的代表,用来将内存中的pages映射为disk blocks,这部分被使用的内存被叫做buffer。

buffer里面的pages,指的是Page cache中的pages,所以,buffer也可以被认为Page cache的一部分。

或者简单来说,buffer负责裸设备相关的缓存,cache负责文件系统的缓存。

Buffer 的具体职责

在当前的系统实现里,buffer主要是设计用来在系统对块设备进行读写时作为缓存来使用。这意味着对块的操作会使用buffer进行缓存,比如我们在格式化文件系统的时候。

但是一般情况下两个缓存系统是一起配合使用的,比如当我们对一个文件进行写操作的时候,cache的内容会被改变,而buffer则用来将cache的page标记为不同的缓冲区,并记录是哪一个缓冲区被修改了。

这样,内核在后续执行脏数据的回写(writeback)时,就不用将整个page写回,而只需要写回修改的部分即可。

Cache 的具体职责

cache主要用来作为文件系统上的文件数据的缓存来用,当进程对文件有read/write操作的时候。包括将文件映射到内存的系统调用mmap,就会用到cache。

因为cache被作为文件类型的缓存来用,所以事实上也负责了大部分的块设备文件的缓存工作。

怎么回收 buff/cache?

Linux内核会在内存将要耗尽的时候,自动触发内存回收的工作,以便释放出内存给急需内存的进程使用。

但是这种回收的工作也并不是没有成本。

理解cache是干什么的就知道,cache中存在着一部分write操作的数据。所以必须保证cache中的数据跟对应文件中的数据一致,才能对cache进行释放。

于是伴随着cache清除的行为的,一般都是系统IO飙高。这是因为内核要将cache中缓存的write数据进行回写。

我们可以使用下面这个文件来人工触发缓存清除的操作,Linux 提供了三种清空方式:

echo 1 > /proc/sys/vm/drop_caches # 仅清除页面缓存

echo 2 > /proc/sys/vm/drop_caches # 清除目录项和inode

echo 3 > /proc/sys/vm/drop_caches # 清除页面缓存、目录项以及inode

但是这种放时只能在执行的当时起作用,过一段时间之后又会发现内存被占满,怎么办呢?

实际上内核提供了vm.vfs_cache_pressure参数用来控制缓冲区的回收频率,我们可以调整它。

这个参数是用来控制内核回收VFS缓存的频率。修改这个值会提高或者降低回收VFS缓存的频率。值可以设置为0-200中的任意值。越大回收频率越快,可以把vm.vfs_cache_pressure赋值为200来获得最快的回收频率。这个值默认值一般为100。

另外也可以使用slabtop分析内存使用情况。一般情况下,dentry和*_inode_cache值越高回收的效果越好。

为什么是dentry和*_inode_cache呢,这是因为当读写文件时内核会为该文件对象建立一个dentry,并将其缓存起来,方便下一次读写时直接从内存中取出提高效率。至于*_inode_cache我就不是很清楚了,只知道是为了加快对索引节点的索引,如果有清楚的可以告诉我一下。

测试一下

首先,我们先看一下目前的内存使用量

core@localhost ~ $ free -h

total used free shared buff/cache available

Mem: 7.8Gi 383Mi 7.1Gi 199Mi 291Mi 7.0Gi

Swap: 0B 0B 0B

生成一个文件测试一下

core@localhost ~ $ dd if=/dev/zero of=testfile bs=1M count=1000

1000+0 records in

1000+0 records out

1048576000 bytes (1.0 GB, 1000 MiB) copied, 1.39192 s, 753 MB/s

检查一下内存的使用情况,是否和上面介绍的一样

core@localhost ~ $ free -h

total used free shared buff/cache available

Mem: 7.8Gi 383Mi 6.1Gi 199Mi 1.3Gi 7.0Gi

Swap: 0B 0B 0B

手动执行一下释放,看能否将内存释放出来

core@localhost ~ $ echo 1 | sudo tee /proc/sys/vm/drop_caches

1

检查一下内存是否被释放掉

core@localhost ~ $ free -h

total used free shared buff/cache available

Mem: 7.8Gi 383Mi 7.1Gi 199Mi 291Mi 7.0Gi

Swap: 0B 0B 0B

继续测试一下读取文件

core@localhost ~ $ time -p cat testfile > /dev/null

real 0.39

user 0.00

sys 0.27

可以看到用时 0.39s,我们看下内存使用

core@localhost ~ $ free -h

total used free shared buff/cache available

Mem: 7.8Gi 382Mi 6.1Gi 199Mi 1.3Gi 7.0Gi

Swap: 0B 0B 0B

然后我们再次执行一下读取文件

core@localhost ~ $ time -p cat testfile > /dev/null

real 0.17

user 0.00

sys 0.17

可以看到用时缩短到了 0.17s,这里需要说明一下的时由于我这边时固态硬盘,所以差距没这么大,如果是机械硬盘的话差距会进一步扩大。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux内存占用过高的情况通常有两种情况:一种是系统占用过多的内存,另一种是进程占用过多的内存。 首先,当系统占用过多的内存,可能是由于以下原因之一: 1. 内核缓存占用过多的内存Linux会将文件系统的数据缓存到内存中,以提访问速度。但是,如果系统内存不足,内核缓存可能会占用大量内存,导致系统运行缓慢。可以通过 `sync` 命令将缓存写入磁盘,或者通过修改 `/proc/sys/vm/drop_caches` 文件来释放缓存。 2. 内存泄漏。某些进程可能会出现内存泄漏问题,导致它们不断分配内存而不释放,最终导致系统内存耗尽。可以使用工具如`top`或`htop`来查看进程的内存使用情况,并尝试终止泄漏的进程。 3. 运行过多的服务或应用程序。如果系统同运行了大量的服务或应用程序,它们可能会竞争系统资源并导致内存占用过高。可以通过停止或优化不必要的服务和应用程序来减少内存占用。 其次,当进程占用过多的内存,可能是由于以下原因之一: 1. 内存泄漏。进程内部可能存在代码bug或设计问题,导致它不断分配内存而不释放,最终导致进程内存占用过高。可以使用工具如`valgrind`来检测和修复内存泄漏问题。 2. 错误的内存使用。进程可能错误地使用了大量的内存,例如无限循环、大量数据拷贝等。可以通过代码审查和性能测试来发现和修复这些问题。 3. 大量数据处理。某些应用程序可能需要处理大量的数据,导致内存占用过高。可以尝试使用更效的算法或数据结构来减少内存使用,或者考虑使用分布式计算或批处理方式来处理数据。 总而言之,当遇到Linux内存占用过高的情况,我们需要先确定是系统占用过多的内存还是某个进程占用过多的内存,并根据具体情况采取相应的解决方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值