服务每隔几天报 OutOfMemoryError: unable to create new native thread,jstack 数出 4120 个线程,其中 3600 个是 pool 开头的业务线程,堆反而不高。乍看像缓存或者权限的锅,追下去往往不是。

jstack 21455 | grep '^"' | cut -d'"' -f2 | cut -d- -f1 | sort | uniq -c | sort -nr
ulimit -u
jcmd 21455 Thread.print | grep -c 'pool-'

追下去是这么回事:每个线程默认占 1MB 栈,4000 个线程光栈就 4G,超过容器的内存上限或 ulimit -u。线程池没有上限,任务一堆积就不断新建。

「native thread 溢出」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。

线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。

权限不要一口气开到最大,先加到够用再往上试,范围小才好收。

具体做法是,把线程池改成有界队列加固定最大线程数;用 jstack 按线程名前缀统计 找出谁在创建;核对容器内存和 ulimit -u 确认是哪一个先到顶;线程栈大小 -Xss 不要盲目调小 先修创建逻辑。

验收就看一点,线程数稳定在 300 以内 运行一周不再出现 native thread 的 OOM。

作者 9823189