前言

最近总算是把博客项目基本写完了,但是部署到服务器上时,服务器直接爆了。。。

但是令人不解的是,服务器4G内存,只用了3G,怎么就用不了了,服务器直接卡死了。

图片

为何为出现如此严重的缩水?

先使用free命令查看下内存情况:

1
$ free

free命令默认以KB为单位,可选参数为:-b、-k、-m、-g

参数说明:

总内存(Total):显示系统的总内存大小。
已使用内存(Used):显示当前已被分配和使用的内存大小。
剩余内存(Free):显示当前剩余可用的内存大小。
共享内存(Shared):显示被多个进程共享的内存大小。
缓存(Buffers):显示用于缓存文件系统数据的内存大小。
缓冲区(Cached):显示用于缓冲磁盘写操作的内存大小。

图片

可以看到总共有3669M可用内存(相当于实际还是缩水了300M。。。),已使用1938M,但是空闲空间只剩141M,缓存占用高达1589M。

为什么缓存占用如此之高呢?

在服务内存够用的情况下,Linux内核为了加快对文件的读写效率会将文件放入之 buffer/cache 中 以保证读写效率,但其实,尽管当你的应用程序对文件的读写运行结束后,buffer/cache 也不会自动释放该部分内存,而是作为缓冲进行保留,等到你的服务进程在下一次进行相同文件的读写时就可以直接使用,省去了各种重新进行内存初始化的操作;所以这将会导致,当你的应用进程频繁对不同的文件进行读写时,你会发现服务所可以直接使用的free内存将会越来越少的一个重要原因;难道 buffer/cache 在这样无休止的缓存当中就不会自动释放?当然不是,当服务器在内存压力较大的情况下时,则将会自动进行内存的回收,作为free空间分给其它进程使用,这其中主要回收的一个内存则是 buffer/cache 的缓冲区内存块。

如何手动回收缓存?

除了在系统进程内存使用较大压力的情况下进行内存的回收外,我们也可以进行手动的buffer/cache回收,但由于buffer/cache主要是用于文件的读写使用,所以进行文件回收时,一般常伴随系统的IO彪高,因为系统内核也对比cache中的数据与硬盘中的数据是否一致,如果不一致需要写入,然后才能进行内存的回收。

1
2
3
4
5
6
7
## 将内存中数据强制先刷新到磁盘中
$ sync

## 清理Buffer缓存区域
# echo 1 > /proc/sys/vm/drop_caches # 表示清除pagecache。
# echo 2 > /proc/sys/vm/drop_caches # 表示清除回收slab分配器中的对象(包括目录项缓存和inode缓存)。slab分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的pagecache。
# echo 3 > /proc/sys/vm/drop_caches # 表示清除pagecache和slab分配器中的缓存对象

非root用户使用以下命令执行:

1
2
3
$ sudo sh -c 'echo 1 > /proc/sys/vm/drop_caches'
$ sudo sh -c 'echo 2 > /proc/sys/vm/drop_caches'
$ sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'

清理完后可以看到可用内存变成了1317M:

图片

排除缓存过高的原因

如果想知道是什么进程引起的缓存过高,可以安装hcache工具进行排查:

1
2
$ wget https://silenceshell-1255345740.cos.ap-shanghai.myqcloud.com/hcache -O /usr/local/bin/hcache ;\
chmod +x /usr/local/bin/hcache

常用命令:

1
2
3
4
5
$ hcache --top 10           # 全局显示10个最大的被缓存文件
$ lsof /usr/lib/vmware-tools/lib64/libxerces-c-3.1.so/libxerces-c-3.1.so
# 根据文件找到对应的进程、pid
$ hcache -pid 1070 # 获取当前进程号所打开的所有文件信息
$ lsof -p 1070 # 获取当前进程号所打开的所有文件信息(二选一)