【Docker 运维】Java 应用在 Docker 容器中启动报错:`unable to allocate file descriptor table`
文章目录
- 一、根本原因
- 二、判断与排查方法
- 三、解决方法
- 1、限制 Docker 容器的文件描述符上限
- 2、在执行脚本中动态设置ulimit的值
- 3、升级至 Java 11+
- 四、总结
容器内执行脚本时报错如下,Java 进程异常退出:
library initialization failed - unable to allocate file descriptor table- out of memory
/entrypoint.sh: line 2: 6 Aborted (core dumped) java ...
一、根本原因
该问题源于 Java 8 的 JDK Bug(JDK-8150460):
- Java 8 在启动时,会尝试根据当前系统
ulimit -n
值,预分配文件描述符表的内存块; - 在现代系统中默认
ulimit -n
值通常为65535
或更高; - 在容器资源受限或配置不当的情况下,native 层内存不足,JVM 启动失败,抛出
unable to allocate file descriptor table
。
此外还有两个系统环境相关的影响:
- 旧版本的 systemd 不支持
LimitNOFILE=infinity
生效; - Docker 容器的默认
ulimit
配置可能不足,或者过大触发此问题。
二、判断与排查方法
## 1. 确认容器内的 `ulimit` 值docker exec <container_id> ulimit -n## 2. 检查系统 systemd 版本
systemctl --version若版本 < 234,`infinity` 设置不会生效。## 3. 确认是否为 Java 8
java -version
三、解决方法
1、限制 Docker 容器的文件描述符上限
将容器启动参数中显式设置 ulimit -n
:
docker run --ulimit nofile=1024:1024 -d -p 8080:8080 your-image
或者在 docker-compose.yml
中配置:
ulimits:nofile:soft: 1024hard: 1024
推荐设置为 8192 以下,如 1024、4096 等。
2、在执行脚本中动态设置ulimit的值
参考:【stackoverflow】Error upon jar execution - unable to allocate file descriptor table
3、升级至 Java 11+
此问题在 Java 9+ 已被修复。
四、总结
项目 | 推荐做法 |
---|---|
问题本质 | Java 8 + 高 ulimit -n 导致 native 层分配失败 |
快速修复 | --ulimit nofile=1024:1024 限制容器文件句柄 |
永久方案 | 配置 systemd 或升级 JDK |
最优解 | 切换 Java 11+,从根源上解决 |