使用FixedThreadPool时内存持续增长的问题排查
解决Executors.newFixedThreadPool()内存持续飙升问题
问题分析
你遇到的内存耗尽问题,核心原因是未清理已处理完成的Future对象引用:
- 代码中
futures列表在循环外部声明,每次while(true)循环都会向其中添加7个新的Future实例; - 调用
future.get()获取结果后,这些Future(以及关联的FutureTask、Lambda对象、队列节点)仍然被futures列表强引用,垃圾回收器无法回收它们; - 随着循环持续执行,列表中的对象数量不断累积,最终导致堆内存耗尽。
即使手动调用System.gc(),由于futures列表还持有强引用,GC只能回收少量临时对象,无法释放Future相关的核心内存,因此内存仍会缓慢增长。堆转储中出现的5万多个FutureTask、LinkedBlockingQueueNode及Lambda对象,正是被futures列表长期引用的结果。
解决方案
将futures列表的声明移至while循环内部,让每次循环产生的Future集合在当前循环结束后失去引用,从而被GC自动回收:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class ExecutorServiceTest { public static void main(String[] args) throws ExecutionException, InterruptedException { int threadCount = 7; ExecutorService executorService = Executors.newFixedThreadPool(threadCount); while (true) { // 每次循环创建新的列表,旧列表无引用后会被GC回收 List<Future<Integer>> futures = new ArrayList<>(); for (int i = 0; i < threadCount; i++) { int finalI = i; futures.add(executorService.submit(() -> { try { Thread.sleep(8000); return finalI; } catch (InterruptedException e) { throw new RuntimeException(e); } })); } for (Future<Integer> future : futures) { System.out.println("Value: " + future.get()); } } } }
额外说明
- 无需手动调用
System.gc():JVM的GC机制会自动处理失去引用的对象,手动调用GC不仅无法解决核心引用问题,还会影响性能; - 若不需要批量处理结果,也可以在提交任务后直接调用
get(),无需存储Future集合,进一步减少内存占用; - 长期运行的线程池建议使用
ThreadPoolExecutor的自定义配置,监控队列长度和线程状态,避免类似内存泄漏问题。
内容的提问来源于stack exchange,提问作者Dioswison
相关产品推荐
相关产品推荐

