导读:本期聚焦于小伙伴创作的《/dev/shm写满导致Tomcat或Java出现OOM时如何调整tmpfs大小限制》,敬请观看详情。把应用日志或文件上传临时目录指向/dev/shm后,不少Tomcat实例在流量高峰突然抛出Java堆外内存溢出。根本原因常是tmpfs默认仅占用物理内存一半,且不加控制就会被写满,触发Linux内核强制回收或进程申请空间失败。与其盲目重启,不如从挂载参数与JVM临时路径两方面入手。可以用mount命令重新指定size参数,把/dev/shm上限设为物理内存的百分之七十五,或在systemd中持久化配置。同时检查Java的java.io.tmpdir是否误设到该分区,改到普通磁盘目录可隔离风险。理清tmpfs与磁盘文件的差异,才能稳定支撑高并发场景下的临时读写需求。

在Linux系统中,/dev/shm是基于tmpfs实现的内存文件系统,常被用作进程间通信或高速临时读写区域。当Tomcat或Java应用将临时文件、上传缓存、会话数据写入该分区,而tmpfs默认大小仅为物理内存的一半且无法动态扩展时,空间很快被占满。此时JVM申请直接内存或本地线程栈失败,就会抛出OutOfMemoryError,这类OOM往往不伴随堆内存报警,排查起来容易误判为代码泄漏。

/dev/shm写满导致Tomcat或Java出现OOM时如何调整tmpfs大小限制

一、tmpfs与/dev/shm的基本机制

tmpfs是一种将数据存储在虚拟内存中的文件系统,它不会写入持久化块设备,读写性能极高,但所占空间会计入内存和swap的使用量。系统启动时,initramfs或systemd会根据内核参数挂载/dev/shm,默认大小为物理内存的一半,可通过df -h /dev/shm查看。

由于tmpfs不具备磁盘后备存储,一旦写入量超过挂载时指定的size,内核会拒绝新的写入并返回ENOSPC错误。Java的FileChannel、RandomAccessFile在收到该错误后,某些第三方库会包装为OOM异常,尤其是使用堆外内存映射文件(MappedByteBuffer)时,表面看像是内存不足,实际是tmpfs配额耗尽。

1.1 查看当前挂载属性

使用以下命令可确认/dev/shm的实际限制与使用情况:

# 查看挂载信息
mount | grep shm
# 查看空间占用
df -h /dev/shm
# 查看系统内存
free -m

若输出中显示size等于内存一半,且Used接近Size,即可判定写满风险。很多运维在排查Tomcat假死时忽略该点,反复调大-Xmx反而让问题更隐蔽。

二、调整tmpfs大小限制的三种方法

解决/dev/shm写满引发OOM的核心思路是合理扩大tmpfs上限,并隔离Java临时目录。下面分别介绍临时调整、持久化配置与JVM层规避。

2.1 使用mount命令临时重挂

在不重启系统的前提下,可重新挂载/dev/shm并指定更大size。该操作立即生效,但重启后失效,适合应急。

# 重新挂载为内存的75%
mount -o remount,size=75% /dev/shm
# 验证
df -h /dev/shm

这种方式的优点是无需停止Tomcat,缺点是若机器重启,配置回退。在临时促销或突发流量时,先这样扩容争取时间,再规划持久方案。

2.2 通过systemd持久化配置

主流发行版使用systemd管理tmp.mount单元,编辑对应配置文件可让size永久生效。

# 复制模板到etcd
cp /usr/share/systemd/tmp.mount /etc/systemd/system/tmp.mount
# 修改Options行,例如设为2G
# [Mount]
# What=tmpfs
# Where=/dev/shm
# Type=tmpfs
# Options=size=2G,nr_inodes=4k
systemctl daemon-reload
systemctl restart tmp.mount

配置后每次启动都会按设定挂载。需注意size不要超过物理内存与swap总和,否则在内存紧张时引发系统级OOM killer。建议结合监控告警,当/dev/shm使用率超百分之八十时自动通知。

2.3 JVM临时目录隔离

Java默认将java.io.tmpdir指向/dev/shm的情况多见于容器环境。可在Tomcat启动脚本中显式指定到其他磁盘路径,避免临时文件挤占tmpfs。

# 在catalina.sh的JAVA_OPTS中加入
JAVA_OPTS="$JAVA_OPTS -Djava.io.tmpdir=/var/tomcat_tmp"

这样上传文件、编译JSP的临时class都不会写入内存分区。配合前面tmpfs扩容,形成双保险。若应用必须利用tmpfs加速,则应单独建一个受限子目录并配额管理。

三、风险对比与选型建议

不同方案在安全性与运维成本上有明显差异,下面用表格归纳。

方案生效范围重启保持风险点
mount remount立即全局重启回退,应急用
systemd tmp.mount开机挂载配置错误致启动失败
java.io.tmpdir改路径单应用失去内存加速优势

对于稳定性优先的生产集群,推荐systemd持久化配合JVM目录隔离。开发测试环境可用临时重挂快速验证。无论哪种方式,都应把/dev/shm监控纳入Prometheus或Zabbix,防止隐性写满。

四、常见误区澄清

有观点认为tmpfs写满只会删文件就好,不必调大小。实际上高并发下删除本身也需内存操作,且某些锁文件被占用无法释放,OOM仍会复现。还有人把/dev/shm当成永久存储,这是概念错误,tmpfs断电即失,不能替代磁盘。

正确做法是:明确临时数据生命周期,给tmpfs设合理上限,并将关键应用临时目录移出内存分区。

通过上述方法,Tomcat与Java进程因/dev/shm耗尽而产生的OOM可被系统性规避,而不是靠频繁重启掩盖问题。

tmpfs/dev/shmJava_OOM修改时间:2026-08-07 14:27:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。