Z次元

文章讨论了云服务器内存占用异常问题,服务器实际可用内存缩水的现象。作者通过free命令分析内存使用情况,发现缓存占用大量内存。解释了Linux内核通过缓存机制优化文件读写效率,但缓存不会自动释放,导致可用内存减少。文章提供了手动清理缓存的方法和工具hcache的使用,帮助诊断内存占用问题。

前言

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

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

图片

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

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

$ 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中的数据与硬盘中的数据是否一致,如果不一致需要写入,然后才能进行内存的回收。

## 将内存中数据强制先刷新到磁盘中
$ 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用户使用以下命令执行:

$ 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工具进行排查:

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

常用命令:

$ 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     # 获取当前进程号所打开的所有文件信息(二选一)

后记

经过了一番折腾总算是把项目部署到云服务器上了。服务器内存直接干掉5个G,3G的物理内存+2G的虚拟内存。

由于项目很多东西都是部署在磁盘转换的虚拟内存上,导致性能不太行,加载速度不是很乐观,只能等后续优化了= =+。

评论区
回复

1

inleft6月6日

java一大特色就是笨重,吃内存,个人服务器如果搭载1个jar包+mysql+es,一套组合拳下来,没有4-5g搞不定,我都是往轻量级的应用走,能不用第三方就自己手写,maven套上一个依赖,给你多整上几个用不到包太常见了,如果有得选,我宁愿学c++

回复

2

博主 @inleft6月7日

emmmm,其实没那么夸张,正常一个java程序大概占用400M左右内存

回复

1

btwoa5月14日

配置高了拿来跑博客还是会心疼的

回复

2

博主 @btwoa5月15日

是的,但是服务器还可以部署其它项目的嘛棒棒糖

回复

1

博主 5月13日

一番折腾下来,发现根本就没用,开个es马上又没内存了,下次得换个更大内存的服务器才行了。。。。

目录