2016-11-07 42 views
4

我有一些函數的大列表(高達500 000)。 我的任務是爲每個函數生成一些圖形(可以獨立於其他函數)並將輸出轉儲到文件(可以是多個文件)。 生成圖的過程可能非常耗時。如何防止在運行並行Java進程時消耗物理內存

我也有40個物理內核和128GB內存的服務器。

我試過用java Threads/ExecutorPool來實現並行處理,但似乎並沒有使用處理器的所有資源。 在某些輸入上,該程序需要長達25小時才能運行,而根據htop,只有10-15個核心正在工作。

所以我嘗試的第二件事是創建40個不同的進程(使用Runtime.exec)並將它們分開。 此方法使用處理器所有資源(所有40個核心上的負載均爲100%),並且前一個示例中的性能提升高達5倍(對於我的任務,這隻需要5個小時)。 但是這個方法的問題是,每個java進程都是獨立運行的,並且獨立於別人使用內存。有些情況下,所有128GB的RAM在並行工作5分鐘後纔會消耗。我現在使用的一種解決方案是,如果Runtime.totalMemory> 2GB,則爲每個進程調用System.gc()。這會降低總體性能(先前輸入爲8小時),但會將內存使用量限制在合理範圍內。 但此配置僅適用於我的服務器。如果您在運行40核心和64GB的服務器上運行它,則需要調整Runtime.totalMemory> 2GB條件。

所以問題是避免這種積極的內存消耗的最好方法是什麼?

運行單獨的進程以執行並行作業是否正常嗎?

在Java中有沒有其他的並行方法(可能是fork/join?),它使用100%物理資源的處理器。

+0

多少個線程是在'Executor'? – kgeorgiy

+0

fork/join在內部使用執行程序池。 – kgeorgiy

+0

是否有原因讓Java不能使用所有128GB的RAM?如果沒有其他需要,它會浪費。自己調用System.gc()並不是一個解決方案,因爲Java很有能力管理自己的內存。 – Kayaman

回答

4

您不需要明確地致電System.gc()! JVM將在需要時自動執行,並且幾乎總是會更好。但是,您應該將最大堆大小(-Xmx)設置爲效果良好的數字。

如果您的程序不會進一步擴展,則會出現某種擁塞。你可以分析你的程序,你的java和系統設置,找出原因,或者把它作爲多個進程運行。如果每個進程多線程,那麼你可以使用5-10的過程,而不是40

請注意,您可以每個核心一個以上的線程得到更高的性能得到更好的性能。每個內核提供1-8個線程,查看吞吐量是否增加。

從您的描述中可以看出,您擁有500,000個完全獨立的工作項目,每個工作項目並不需要太多內存。如果那是真的,那麼內存消耗並不是真正的問題。只要每個進程都有足夠的內存,所以它不必經常使用gc,那麼gc不會影響總執行時間。只要確保你沒有任何不再需要的對象的懸掛引用。