Jetty线程数超出start.ini配置值的原因及内存疑问
Jetty线程池配置与实际线程数不符问题解答
问题背景
将Java Spring应用部署在Jetty 9.4.8环境中,已在start.ini里把jetty.threadPool.maxThreads设为1000,但通过htop查看线程数约3030,用ps命令统计Jetty线程数达2876,远高于配置上限。同时Jetty占用120/125G内存却未触发OOM。
1. 该统计线程数是否可与maxThreads对比?
不能直接对比。jetty.threadPool.maxThreads控制的只是Jetty核心业务线程池的最大线程数——也就是处理HTTP请求的工作线程数量。而htop或ps统计的是整个JVM进程的所有线程,除了Jetty的业务线程,还包括:
- JVM自身的后台线程(比如GC线程、JIT编译线程、信号处理线程)
- Spring框架的内部线程(比如定时任务线程、异步处理线程、事件监听线程)
- 应用代码自己创建的线程(比如自定义线程池、异步任务线程)
- Jetty的其他辅助线程(比如acceptor线程、selector线程、连接清理线程等)
2. maxThreads为何未限制线程数量?
因为maxThreads的作用范围有限,它只约束Jetty的主请求处理线程池,管不了其他来源的线程:
- 如果你在Spring应用里用了
@Async、ThreadPoolTaskExecutor这类组件,这些线程不受Jetty线程池配置管控 - JVM会根据GC策略自动创建多个GC线程(比如Parallel GC会根据CPU核心数生成对应数量的GC线程)
- Jetty本身除了业务线程池,还有负责监听端口的acceptor线程、处理NIO事件的selector线程,这些都不在
maxThreads的管控范围内
3. 现有线程与运行线程数量差距大的原因?
这里的“差距大”是指统计的总线程数远大于maxThreads配置值,核心原因是统计的是进程全量线程,而maxThreads只覆盖Jetty的业务处理线程。另外,还可能存在大量处于WAITING/TIMED_WAITING状态的空闲线程:
- 比如Spring的异步线程池、自定义线程池里的核心线程,即使没有任务也会保持存活
- Jetty线程池里的空闲线程也会处于等待状态,直到有新请求进来
- JVM的一些后台线程平时也处于休眠等待状态,只有特定触发条件才会活跃
4. 大量线程是否影响内存占用?
肯定会影响。每个Java线程都需要占用一定的内存:
- 线程栈内存:默认每个线程栈大小是1MB(可通过
-Xss参数调整),2800个线程光栈内存就占了2.8GB左右 - 线程的内部数据结构(比如Thread对象、栈帧、本地变量表等)也会占用堆内存
- 如果线程持有大量对象引用,会导致GC无法回收这些对象,间接增加内存占用
至于未触发OOM,可能是因为:
- 剩余的5G内存刚好能支撑线程相关内存和其他堆内存的开销
- 应用的堆内存设置足够大(比如
-Xmx设到了120G左右),线程栈内存属于非堆内存,没占用堆的配额 - 当前大部分线程处于空闲状态,没有持有大量活跃对象,GC能正常回收无用对象
内容的提问来源于stack exchange,提问作者Dmitry Sheykin
相关产品推荐
相关产品推荐

