【问题标题】:FixedThreadPool memory leak固定线程池内存泄漏
【发布时间】:2017-12-07 04:10:15
【问题描述】:

我有一个Stream<String> 并对其项目执行一些操作,包括处理字符串并将其写入文件。

拥有以下 groovy 代码,并处理 100 万个项目,我遇到了 OutOfMemoryError

ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())

stream.forEach { item ->
    executorService.execute {
        handle(item)
    }
}

executorService.shutdown()
executorService.awaitTermination(1, TimeUnit.DAYS)

经过一些分析,我发现 Runnable 任务不是由 gc 处理的,而是 在 BlockingQueue 中保持活动状态,直到应用程序失败。

为什么 ExecutorService 将完成的 Runnable 保留在队列中?以及应该如何清理?

【问题讨论】:

  • 它没有。你的诊断是错误的。队列包含在执行之前等待的任务。
  • 这听起来不太可能——为了让队列中的项目执行它,它必须被删除。因此,如果他们留在队列中,他们就不会真正被执行。
  • @AndyTurner 的意思是我应该尝试减少队列大小?在那种情况下会发生什么?
  • Runnables 几乎没有任何状态,创建 100 万个 Runnables 不会消耗太多内存。你需要弄清楚到底是什么吃掉了那段记忆。 handle() 有什么作用?
  • 您可以使用有界队列,并使用docs.oracle.com/javase/8/docs/api/java/util/concurrent/…。但是,如果您发布代码并准确地解释它应该做什么,那么提供帮助会容易得多。

标签: java multithreading groovy memory-leaks threadpoolexecutor


【解决方案1】:

内存泄漏是因为 BlockingQueue 被填满的速度比 ExecutorService 从中拉出任务的速度快。

这是因为使用forEach 方法对流进行迭代非常快,但任务运行时间更长。

这是我应用的解决方案

def processors = Runtime.getRuntime().availableProcessors()
ExecutorService executorService = new ThreadPoolExecutor(
    processors, processors,
    0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>(1000),
    new ThreadPoolExecutor.CallerRunsPolicy()
)

这基本上只是限制 BlockingQueue 的大小,并确保如果队列已满,主线程将接手工作。

感谢@JBNizet 和其他人对上述 cmets 的帮助。

【讨论】:

    猜你喜欢
    • 2018-12-18
    • 2015-05-20
    • 2012-05-12
    • 2014-12-30
    • 2014-10-29
    • 2013-12-18
    • 2017-02-04
    • 2016-12-09
    • 2020-08-08
    相关资源
    最近更新 更多