java.lang.OutOfMemoryError: Unable to create new native thread 是因系统线程数达上限或单线程栈过大导致,需调小 -Xss、禁用 newCachedThreadPool、改用有界线程池、检查第三方库线程配置、确认 ulimit -u 和内核限制,并排查线程泄漏。
这个错误不是堆内存不足,而是操作系统无法为 jvm 分配新的本地线程。根本原因在于线程创建时需占用系统资源(如栈空间、线程描述符、内核结构体等),当达到 os 或 jvm 限制时就会抛出该异常。
检查并降低单个线程的栈大小(-Xss)
JVM 默认线程栈大小通常为 1MB(64位 Linux/OpenJDK),大量线程会快速耗尽虚拟内存或地址空间。例如:1024 个线程 × 1MB ≈ 1GB 地址空间 —— 在 32 位 JVM 或内存受限容器中极易触发。
- 查看当前设置:
java -XX:+PrintFlagsFinal -version | grep ThreadStackSize - 合理调低(如 256KB 或 512KB):
-Xss256k(注意:过小可能导致 StackOverflowError,尤其递归深或框架栈开销大) - Spring Boot 应用常见于异步任务、WebSocket 连接、定时任务等场景,可针对性调整相关线程池的
threadFactory并设较小栈
限制应用创建的线程总数
多数业务无需成百上千线程。无节制使用 new Thread()、未配置大小的 Executors.newCachedThreadPool()、或未复用的连接池(如 HTTP 客户端、数据库连接)是主因。
- 禁用
Executors.newCachedThreadPool()—— 它的无界队列 + 无限创建线程极易失控 - 改用有界线程池:
new ThreadPoolExecutor(core, max, keepAlive, unit, new LinkedBlockingQueue(queueSize)) - 检查第三方库:OkHttp(connectionPool)、HikariCP(maximumPoolSize)、RabbitMQ(work queue consumers)、Netty(eventLoopGroup 线程数)等均需显式设上限
确认系统级线程限制(ulimit / kernel 参数)
Linux 中每个进程能创建的线程数受 RLIMIT_NPROC(用户进程/线程数上限)和 /proc/sys/kernel/threads-max 共同约束。
- 查看当前限制:
ulimit -u(每个用户进程数,含线程);cat /proc/sys/kernel/threads-max - 临时提高(需 root):
ulimit -u 65535;echo 131072 > /proc/sys/kernel/threads-max - Docker 容器默认继承宿主机 ulimit,但可能被
--ulimit覆盖,启动时显式指定:docker run --ulimit nproc=65535:65535 ...
排查隐式线程泄漏
线程未正确关闭(如未 shutdown 的 ScheduledExecutorService、未 close 的 ForkJoinPool、未释放的 ThreadLocal 持有对象)会导致线程长期存活,数量持续增长。
立即学习“Java免费学习笔记(深入)”;
- 用
jstack <pid>查看线程列表,重点关注WAITING或TIMED_WAITING状态的线程是否异常堆积 - 对比多次 jstack 输出,观察线程名(如
pool-1-thread-xx、http-nio-8080-exec-xx)是否持续递增 - 检查代码中所有
new ScheduledThreadPoolExecutor、ForkJoinPool.commonPool()、CompletableFuture异步调用是否伴随生命周期管理
不复杂但容易忽略 —— 关键是把“线程”当作和数据库连接、文件句柄同等重要的有限资源来管控。



















