【问题标题】:Java Executor Service - Out Of MemoryJava 执行器服务 - 内存不足
【发布时间】:2021-03-25 05:39:54
【问题描述】:

我正在使用 java 执行器服务将数据从一个数据库传输到另一个数据库。

ExecutorService executor = (ExecutorService) Executors.newFixedThreadPool(10);

一旦执行器服务被初始化。以 500 条为一组从源数据库中检索记录,并将这些记录索引到目标数据库中。

while(true){  
   List<?> docs = getDataFromSourceDB();
   if(docs.size > 0){
       IndexdataToTargetDBThread thread = new IndexdataToTargetDBThread(docs)
       executor.submit(thread);
   }else{
        break;
   }
} 

executor.shutdown()
while (!eService.isTerminated()) {
}

函数getDataFromSourceDB() 在每次调用时返回 500 条记录,如果没有可用记录,它将返回一个空数组。 IndexdataToTargetDBThread 类实现了 Runnable。它将给定文档索引到目标数据库。

上述函数运行时出现Out Of Memory异常。 Source DB 有接近 1M 的记录,因此 while 循环被处理了大约 2000 次。处理大约 700 次后,出现内存不足,整个 DB 传输过程失败。有没有有效的方法来处理这个问题?

【问题讨论】:

  • 也许不要同时保留这么多未完成的工作。跟踪未完成的工作数量,如果超过 100 个,请在排队之前等待。在之前的工作完成之前,它们不会被执行。
  • 您没有使用执行程序来限制负载。您在提交到线程池时获取所有数据。您应该在 Runnable 的 run() 方法中调用 getDataFromSourceDB(),以便在任何给定时间最多加载 (500*10) 条记录。
  • 可以给我IndexdataToTargetDBThread课的内容吗?也许你没有打电话给EntityManager.clear()
  • @dungtavan :这有一些我无法掩盖和分享的机密信息。但是,写入目标数据库处理得很好。不使用 EntityManager.clear()。数据库连接已正确打开、处理和关闭。就像 ernest 提到的那样,我试图限制流入数据。
  • 顺便说一句……用executor.awaitTermination()替换那个紧密的循环while (!eService.isTerminated()) {}

标签: java multithreading executorservice


【解决方案1】:

我看到了两个问题。 首先,它是从数据库中获取的无限数据大小。您可以限制应用程序中同时存在的记录数。创建缓冲区(它可能是一个元素有限的队列)并在准备好写入后刷新批处理:https://docs.oracle.com/javase/8/docs/api/java/util/Queue.html)

第二:不确定数据库的隔离级别。下一篇介绍PostgreSQL中并发插入的一些问题:https://www.postgresql.org/files/developer/concurrency.pdf

另外,您可以尝试通过 -Xmx .. 选项增加 java 内存限制: Increase heap size in Java

但这不是最好的方法:)

【讨论】:

    猜你喜欢
    • 2012-05-06
    • 2014-10-04
    • 2012-07-05
    • 2014-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多