Jib打包SpringBoot容器启动报pthread_create failed (EPERM)如何排查
问题背景
- SpringBoot应用通过Jib 3.2.0打包为Docker镜像,基础镜像采用Temurin JDK 17.0.3+7
- 在故障Linux服务器(Docker版本20.10.4)上启动容器时立即崩溃,启动日志报错如下:
[0.012s][warning][os,thread] Failed to start thread - pthread_create failed (EPERM) for attributes: stacksize: 1024k, guardsize: 4k, detached. # # There is insufficient memory for the Java Runtime Environment to continue. # Cannot create worker GC thread. Out of system resources. # An error report file with more information is saved as: # //hs_err_pid1.log
- 容器启动后直接退出,无法通过
docker exec进入容器查看hs_err_pid1.log文件 - 容器使用特权模式启动可正常运行,但不符合安全规范要求
- 提前释放4G可用内存后问题仍复现,使用
docker run、docker-compose两种方式启动结果一致 - 相同镜像在硬件配置相近的其他服务器上可正常启动运行
根因分析
该报错和宿主机实际剩余内存无关,是安全规则拦截导致的JVM误报:
- Temurin JDK 17.0.3版本创建线程时会调用
clone3系统调用 - Docker 20.10.4是20.10系列的早期版本,默认内置的seccomp安全配置未将
clone3加入允许列表,会直接拦截该系统调用并返回EPERM(操作无权限)错误 - JVM未识别到该错误属于权限拦截,误判为系统内存不足无法创建GC工作线程,最终抛出内存不足的错误日志
- 特权模式会绕过所有seccomp安全限制,因此容器可以正常启动;其他可正常运行镜像的服务器,大概率Docker版本更高,默认seccomp配置已经兼容
clone3系统调用,因此不会触发该问题。
解决方案
按推荐优先级从高到低排序:
- 方案一(生产环境首选):将故障服务器的Docker版本升级到20.10.9及以上,该版本之后的Docker默认seccomp配置已经加入
clone3系统调用的允许规则,无需额外修改启动参数即可兼容JDK17,无额外安全风险。 - 方案二(无法升级Docker时使用):启动容器时手动指定兼容
clone3规则的seccomp配置文件,启动命令添加参数:
该方案不需要放开全量权限,仅补充缺失的系统调用允许规则,安全风险远低于特权模式。--security-opt seccomp=/path/to/your/compatible-seccomp.json - 方案三(临时应急使用):通过JVM启动参数降低GC线程数,减少线程创建触发频率,添加参数如下:
注意:该方案属于临时规避手段,GC线程数过低会影响应用垃圾回收性能,不建议生产环境长期使用-XX:ParallelGCThreads=2 -XX:ConcGCThreads=1 - 补充排查项:执行
docker info | grep Pids查看Docker默认的进程数限制,如果默认pids limit低于1024,启动容器时可添加--pids-limit=2048设置合理的进程数阈值,排除进程数限制导致的线程创建失败问题。
内容的提问来源于stack exchange,提问作者Ruokki
相关产品推荐
相关产品推荐

