2016-05-19 8 views
5

私は問題を説明するために簡単に試みます。私は商品/ SKUを扱うサプライチェーンドメインで働いています。Javaガベージコレクタによるパフォーマンスの低下?提案が必要です

私の問題はすべて100万SKUであり、アルゴリズムを実行しています。 私のJVMヒープサイズは4 GBです。

多くのメモリが必要になるため、すべてのSKUをワンショットで処理することはできません。 したがって、問題のセットをより小さなバッチに分割します。各バッチには、一緒に処理する必要があるすべての関連するSKUがあります。

ここでは、データセット全体を処理するためにいくつかの繰り返しを実行します。もし、各バッチが約保持しているとします。 5000 SKU、私は200反復/ループがあります。バッチが処理を完了するまで、5000 SKUのすべてのデータが必要です。しかし、次のバッチが開始されると、以前のバッチデータは不要となり、ガベージコレクションが可能になります。

これは問題の背景です。さて、GC - のために特定のパフォーマンスの問題に遭遇しました。各バッチは約2〜3秒で完了しています。さて、GCは、特定のバッチの処理が終わるまで、すべてのデータが必要になるため、この時間内にオブジェクトを解放することはできません.Goはこれらのオブジェクトをすべて古いGenに移動します(yourkitプロファイラを見ると、新世代ではほとんど何もない)。だから、古い世代はより速く成長しており、完全なGCが必要になり、私のプログラムは非常に遅くなります。このような場合にGCをチューニングする方法はありますか、または別の方法でメモリ割り当てを行うために自分のコードを変更することはできますか?

PS - 各バッチが非常に小さい場合、この問題は表示されません。これは、GCがバッチ処理が高速に完了し、古いジェネレーション内のオブジェクトを移動する必要がないため、オブジェクトを十分に高速に解放できるためです。

+0

**プロファイラ**は、ガベージコレクタの10%以上を占めていると伝えましたか?またはそれは推測ですか? – RobAu

+0

テンチャリングしきい値を変更します。どのようにあなたのGCに依存する - どのGCを使用していますか? –

+0

Full GCの継続時間はどのくらいですか? –

答えて

3

First Google hitは、-XX:NewRatioを使用して古い世代に比べて大きな世代サイズを設定できることを示しています。

+1

新しい新世代の収集時間が増加します。新しいgenのサイズをもっと大きくすると、新しいgenを古いgenとして扱います。これは、古い世代GC時間と比較して、同様のGC時間を要する。この場合、IMOのGCポリシーはあまり役に立たないでしょう。私が間違っている場合は修正してください。 –

+1

@nachiketkate良い点。私は確かに専門家ではありませんが、私の理解はいつもそうでした[古い世代より若い世代のGCよりも効率的だというのはよく知られています](http://www.javaspecialists.eu/archive/Issue115.html)。しかし、おそらくその比較は、若い世代が古いものよりも小さいと仮定すると、不公平です。 –

1

他の答えで説明したように、-XX:NewRatioを調整する必要があります。

-XX:NewRatio = 1これは、古い世代と若い世代が利用可能なヒープメモリを均等に分割することを意味します。このフラグは、他のメモリ調整フラグと一緒にどのように機能するかについて

詳細:https://docs.oracle.com/cd/E19900-01/819-4742/abeik/index.html

+0

既に新しい比率で演奏されています...ある程度までは助けましたが、限界があると言ったときには – Shiladitya

+0

、あなたが試したNewRatiosは何ですか?改善は何ですか? – Vijay

+0

私はNEWRATIO = 3/4で最高のパフォーマンスを得ています。 – Shiladitya

1

object pool patternを使用することを検討してください。

I.e. 5000 SKUのプルを作成し、各バッチに対してこれらのオブジェクトのそれぞれを新しいデータで初期化します。 このようにして、GCには何の問題もなくなります。

+0

ありがとう、私は同様のsometihngを試みています。しかし、多くの成功 – Shiladitya

0

いくつかのヒント:visualvmまたはMAT

  • のようなプロファイリングツールでメモリリークのため

    1. チェックあなたがメモリリークを持っていない場合は、チェック現在のメモリが十分であるかどうか。そうでない場合は、十分なメモリを割り当てます。
    2. 問題文から、oldGenが増えており、それはFullGCです。あなたは使用しているガベージコレクタを引用していませんでした。メモリ> = 4GBを使用しているので、G1GCのアルゴリズムを試してください。 G1GCでは、pause time goal, region size, parallel gc threads etcのようなキーパラメータの設定を除いてほとんどのデフォルト値を保持することができます。

    詳細については、このSEの質問を参照してください。私は、これは少し遅れてまだある知っている

    Java 7 (JDK 7) garbage collection and documentation on G1

  • 0

    ..

    私はに助けJVM GCオプションでたくさんの周りを果たしました少し程度。良いことは、私は多くのプロセスでのGCについて学んだことです:

    最後に、私はオブジェクトプーリングのいくつかの並べ替えをしました。 ジョブはバッチで処理され、各バッチはおおよそ同じサイズで同じ数のオブジェクトを使用するため、バッチごとにオブジェクトを作成および破棄するのではなく、バッチごとにリサイクルされたオブジェクトのプールを作成しました。 すべてのバッチの終わりに、私はオブジェクト(配列-1など)をリセットしています。 そして、次のバッチの始めに、それらのオブジェクトを再初期化することによってそれらのオブジェクトを再利用しています。また、マルチスレッドの場合、これらのプールは同期オーバーヘッドを避けるためにThreadLocalsになります。

    関連する問題