3

JavaのGCで非常に奇妙な問題が発生します。私は次のコードを実行しています:

 while(some condition){
        //do a lot of work...
        logger.info("Generating resulting time series...");
        Collection<MetricTimeSeries> allSeries = manager.getTimeSeries();
        logger.info(String.format("Generated %,d time series! Storing in files now...", allSeries.size()));

        //for (MetricTimeSeries series : allSeries) {
           // just empty loop
        //}
 }

JConsoleを調べると、すべてのループ反復の再開時に、手動でGCを強制した場合、古いgenヒープスペースのサイズは約90MBになります。このようにループのコメントを外すと

 while(some condition){
        //do a lot of work...
        logger.info("Generating resulting time series...");
        Collection<MetricTimeSeries> allSeries = manager.getTimeSeries();
        logger.info(String.format("Generated %,d time series! Storing in files now...", allSeries.size()));

        for (MetricTimeSeries series : allSeries) {
           // just empty loop
        }
 }

強制的に更新しても、550MBを下回ることはありません。yourKitプロファイラーによると、TimeSeriesオブジェクトは、新しい反復の再開時のGCの直後に、メインスレッドのローカル変数(コレクション)を介してアクセスできます...そしてコレクションは膨大です(250K時系列)... Wyy isこれが起こって、どうすればこの(間違った?)行動と「戦う」ことができますか?

4

2 に答える 2

2

うん、ガベージコレクターは不思議かもしれません..しかし、それはあなた自身の記憶を管理するよりも優れています;)

コレクションとマップには、必要以上に長く参照にぶら下がる方法があり、予想どおりにガベージコレクションを防ぐことができますお気づきのように、allSeries参照をnullそれ自体に設定すると、ガベージコレクションの対象として耳にマークが付けられるため、その内容も取得できます。別の方法は、呼び出すことallSeries.clear()です。これにより、すべてのオブジェクトのリンクが解除さMetricTimeSeriesれ、ガベージコレクションが無料になります。

ループを削除すると、この問題も回避されるのはなぜですか?これはもっと興味深い質問です。コンパイラが..への参照を最適化していることを示唆したくなりallSeriesますが、まだ呼び出しているため、参照を完全に最適化するallSeries.size()ことはできません。

水を濁らせるために、異なるコンパイル(および設定)は異なる動作をし、それ自体が異なる動作をする異なるガベージコレクターを使用します。これ以上の情報がなければ、内部で何が起こっているのかを正確に言うのは難しいです。

于 2012-12-15T16:26:27.480 に答える
1

(大きな)ArrayList時系列を構築しているので、参照されている限りヒープを占有し、十分に長くとどまる場合(または若い世代が小さすぎて実際に保持できない場合)に古いものに昇格します。JConsoleまたはYourkitに表示されている情報をプログラムの特定のポイントにどのように関連付けるかはわかりませんが、空のループが複数のJITパスによって最適化されるまで、whileループに時間がかかり、コレクションが長くなります。 、実際にはそれほど多くはありませんが、知覚される違いを説明する可能性があります。

その振る舞いについては何も間違っていません。あまり多くのメモリを消費したくない場合は、変更する必要があります。Collectionこれは、熱心に満たされるのArrayListではなく、怠惰なコレクションであり、より多くのストリームです(XML処理を行ったことがある場合は、DOMとSAXを考えてください)。繰り返されるときに評価されます。コレクション全体を並べ替える必要がない場合、特にコレクションは基になるオブジェクトによって返されるサブコレクションの連結であると言っているように見えるため、これは実行可能です。

Collectionリターンタイプをからに変更できる場合Iterableは、たとえば、Guavaを使用して、基になるオブジェクトのFluentIterable.transformAndConcat()コレクションをIterableそれらの時系列の遅延評価された連結に変換できます。もちろん、コレクションのサイズはもう直接利用できません(反復とは別に取得しようとすると、遅延コレクションを2回評価します)。

于 2012-12-16T22:18:45.163 に答える