如何在运行并行Java进程时防止物理内存消耗

如何在运行并行Java进程时防止物理内存消耗,java,multithreading,parallel-processing,Java,Multithreading,Parallel Processing,我有一些函数的大列表(多达50万个)。 我的任务是为每个函数生成一些图形(可以独立于其他函数进行),并将输出转储到文件(可以是多个文件)。 生成图形的过程可能非常耗时 我也有40个物理核心和128GB内存的服务器 我曾尝试使用java线程/ExecutorPool实现并行处理,但它似乎没有使用处理器的所有资源。 在一些输入上,程序运行时间长达25小时,根据htop,只有10-15个芯在工作 因此,我尝试的第二件事是创建40个不同的进程(使用Runtime.exec)并在其中拆分列表。 此方法使用

我有一些函数的大列表(多达50万个)。 我的任务是为每个函数生成一些图形(可以独立于其他函数进行),并将输出转储到文件(可以是多个文件)。 生成图形的过程可能非常耗时

我也有40个物理核心和128GB内存的服务器

我曾尝试使用java线程/ExecutorPool实现并行处理,但它似乎没有使用处理器的所有资源。 在一些输入上,程序运行时间长达25小时,根据htop,只有10-15个芯在工作

因此,我尝试的第二件事是创建40个不同的进程(使用Runtime.exec)并在其中拆分列表。 此方法使用处理器所有资源(所有40个核上都有100%的负载),并将性能提高到上一个示例的5倍(仅需5小时,这对于我的任务来说是合理的)。 但这种方法的问题是,每个java进程都单独运行,并且独立于其他进程消耗内存。在某些情况下,并行工作5分钟后会消耗所有128gb的ram。我现在使用的一种解决方案是,如果Runtime.totalMemory>2GB,则为每个进程调用System.gc()。这会稍微降低总体性能(在以前的输入中为8小时),但会使内存使用保持在合理的范围内。 但此配置仅适用于我的服务器。如果在40核、64GB运行的服务器上运行,则需要调整Runtime.totalMemory>2GB条件

所以问题是什么是避免这种攻击性内存消耗的最佳方法

运行单独的进程来执行并行作业是正常做法吗


Java中是否有其他并行方法(可能是fork/join?)使用处理器100%的物理资源

您不需要显式调用
System.gc()
!JVM会在需要时自动完成,而且几乎总是做得更好。但是,您应该将最大堆大小(
-Xmx
)设置为一个工作正常的数字

如果你的程序不能进一步扩展,你会遇到某种阻塞。您可以分析您的程序、java和系统设置并找出原因,或者将其作为多个进程运行。如果每个进程都是多线程的,那么使用5-10个进程而不是40个进程可能会获得更好的性能

请注意,如果每个核心有多个线程,您可能会获得更高的性能。在每个内核中使用1-8个线程,看看吞吐量是否会增加


根据您的描述,听起来您有500000个完全独立的工作项,每个工作项实际上并不需要很多内存。如果这是真的,那么内存消耗就不是真正的问题。只要每个进程都有足够的内存,因此不需要经常进行gc,那么gc就不会对总执行时间产生太大的影响。只需确保没有对不再需要的对象的任何悬空引用。

这里的问题之一:仍然很难理解有多少线程、内核。。。它们实际上是可用的

我个人的建议是:java专家时事通讯上有几篇文章对此主题进行了深入的探讨

例如,这个:


或者最近一个新的,关于“可用处理器的数量”:

您的
Executor
中有多少个线程?Fork/join在内部使用Executor池。有什么原因不能让Java使用所有128GB的RAM?如果没有其他东西需要它,它就会浪费掉。您自己调用
System.gc()
也不是一个解决方案,因为Java完全能够管理自己的内存。另外,如果您的进程是多线程的,您可能不应该运行其中的40个。@kgeorgiy我已经试过Runtime.getRuntime().availableProcessors()+1和Runtime.getRuntime().availableProcessors()*2,没有实际的区别