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

时间:2016-11-07 07:38:28

标签: java multithreading parallel-processing

我有一些功能的大名单(最多500 000)。 我的任务是为每个函数生成一些图形(它可以独立于其他函数)并将输出转储到文件(它可以是几个文件)。 生成图形的过程可能非常耗时。

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

我曾尝试使用java Threads / ExecutorPool实现并行处理,但似乎没有使用处理器的所有资源。 在某些输入上,程序运行最多需要25个小时,根据htop,只有10-15个核心正在运行。

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

所以问题是避免这种积极的记忆消耗的最佳方法是什么?

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

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

2 个答案:

答案 0 :(得分:4)

您不需要明确致电System.gc()! JVM将在需要时自动执行,并且几乎总是做得更好。但是,您应该将最大堆大小(-Xmx)设置为运行良好的数字。

如果您的计划未能进一步扩展,则会出现某种拥堵现象。您可以分析程序和java和系统设置,找出原因,或将其作为多个进程运行。如果每个进程都是多线程的,那么使用5-10个进程而不是40个进程可以获得更好的性能。

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

从您的描述中可以看出,您有500,000个完全独立的工作项目,并且每个工作项目并不需要大量内存。如果这是真的,那么内存消耗并不是真正的问题。只要每个进程都有足够的内存,因此它不必经常使用gc,那么gc不会对总执行时间产生太大的影响。请确保您没有任何悬挂式引用您不再需要的对象。

答案 1 :(得分:2)

其中一个问题是:仍然很难理解有多少线程,核心......实际可用。

我的个人建议:java专家时事通讯上有几篇文章深入探讨了这一主题。

例如这一个:http://www.javaspecialists.eu/archive/Issue135.html

或更近期的新内容,"可用处理器的数量":http://www.javaspecialists.eu/archive/Issue220.html