java临时目录(如/tmp)被写满会导致“no space left on device”错误,根源是jvm默认临时路径空间不足且文件未及时清理;必须在启动时用-djava.io.tmpdir指定有权限、足空间的目录并验证生效,同时主动管理临时文件生命周期。

Java临时目录被写满导致java.io.IOException: No space left on device
Java很多操作(比如解压JAR、生成JVM临时类、javax.imageio读图、ZipFile打开压缩包)会默认往系统临时目录写文件。Linux/macOS下是/tmp,Windows下是%TEMP%。这个目录通常挂载在小容量分区(比如/tmp只有1GB),一旦被Java进程反复创建临时文件又没及时清理,就直接报No space left on device——哪怕磁盘总空间还剩几十G。
- 不是Java堆内存不足,也不是磁盘真的满了,而是
/tmp分区撑爆了 - 常见于高频调用
ImageIO.read()、URLClassLoader动态加载、Spring Boot DevTools热重载等场景 - 某些容器环境(如Docker)默认
/tmp是tmpfs内存文件系统,大小固定(常为64MB),更容易瞬间打满
如何安全地指定Java临时目录(java.io.tmpdir)
必须在JVM启动时通过-Djava.io.tmpdir=设置,运行时改System.setProperty("java.io.tmpdir", ...)无效——因为很多底层类(如java.io.File的静态初始化块)在JVM启动早期就已读取并缓存该值。
- 推荐路径:指向一个有足够空间、且应用有读写权限的目录,例如
-Djava.io.tmpdir=/var/tmp/myapp-tmp - 避免使用用户家目录下的
~/tmp——如果JVM以root运行,而~展开成/root,其他用户进程可能无权访问 - 容器中务必挂载宿主机目录到该路径,并设好权限(如
chown -R 1001:1001 /var/tmp/myapp-tmp) - 不要用相对路径,JVM不会按你预期的工作目录解析它
java.io.tmpdir和java.lang.System.getProperty("os.name")的关系
这个系统属性本身不依赖操作系统类型,但它的默认值会变。关键是:不同OS默认值的生命周期、清理策略、权限模型差异极大,不能假设“Linux下/tmp自动清理所以不用管”。
- macOS的
/tmp由periodic脚本每天清理,但Java进程可能在清理前就写爆它 - systemd系统(CentOS 7+/Ubuntu 16.04+)的
/tmp可能是tmpfs或绑定挂载,df -h /tmp才能确认真实大小 - Windows上
%TEMP%若指向C:\Users\xxx\AppData\Local\Temp,可能受OneDrive/组策略同步影响,出现权限拒绝或延迟写入 - 永远用
System.out.println(System.getProperty("java.io.tmpdir"))验证实际生效值,别信文档或配置注释
临时目录泄漏:为什么清空java.io.tmpdir后仍报错
Java自身不负责删除临时文件,全靠开发者显式调用File.deleteOnExit()或Files.deleteIfExists()。但很多库(尤其是老版本Apache Commons IO、早期Spring)会创建临时文件却不清理,或者只在JVM正常退出时清理——而OOM、kill -9、容器重启都会跳过deleteOnExit逻辑。
立即学习“Java免费学习笔记(深入)”;
- 检查
java.io.tmpdir下是否有大量jetty-*、jar_cache_*、sunpkcs11-*等前缀文件 - 用
lsof +D /path/to/tmp(Linux)或handle.exe -p java(Windows)确认是否还有进程持有已删文件句柄 - 生产环境建议加定时任务清理:例如
find /var/tmp/myapp-tmp -name "*" -mmin +60 -delete(注意避开正在使用的文件) - 更可靠的做法是:用
Files.createTempDirectory()代替Files.createTempFile(),把相关临时资源组织进独立子目录,便于整目录原子清理
java.io.tmpdir就一劳永逸,却没验证它是否真被JVM读取,也没监控该目录的inode占用和文件残留。










