4

1 つの整数変数を持つ非常に単純なクラスがあります。変数 'i' の値を画面に表示してインクリメントし、スレッドを 1 秒間スリープさせます。このメソッドに対してプロファイラーを実行すると、新しい変数を作成していないにもかかわらず、メモリ使用量がゆっくりと増加します。このコードを約 16 時間実行した後、メモリ使用量が 4 MB に増加したことがわかりました (プログラムを開始したときは、最初は 1 MB でした)。私はJavaの初心者です。どこが間違っているのか、または新しい変数が作成されていないのにメモリ使用量が徐々に増加しているのはなぜですか? 前もって感謝します。

私は netbeans 7.1 とそのプロファイラーを使用してメモリ使用量を表示しています。

    public static void main(String[] args)
    {
        try
        {
            int i = 1;
            while(true)
            {
                System.out.println(i);
                i++;
                Thread.sleep(1000);
            }
        }
        catch(InterruptedException ex)
        {
            System.out.print(ex.toString());
        }
    }

プログラム開始時の初期メモリ使用量: 1569852 バイト。

ループを 16 時間実行した後のメモリ使用量: 4095829 バイト

この投稿のコードで直面している問題のスクリーンショット

4

7 に答える 7

2

必ずしもメモリ リークではありません。GC が実行されると、ステートメントで割り当てられたオブジェクト (推測)System.out.println(i);が収集されます。Java でのメモリ リークは、GC で回収できない無駄なオブジェクトでメモリがいっぱいになることです。

を文字列に変換するためにprintln(i)使用しており、毎回新しいものを割り当てています。String が出力バッファにコピーされると到達不能になり、GC の候補になるため、これはリークではありません。Integer.toString(int)intString

メモリ割り当てのその他の可能なソース:

  • Thread.sleep は、カバーの下にオブジェクトを割り当てている可能性があります。

  • 一部のプライベート JVM スレッドが原因である可能性があります。

  • プロファイラーが JVM の状態を監視するために使用している「Java エージェント」コードが原因である可能性があります。ソケットを介してデータをアセンブルし、プロファイラー アプリケーションに送信する必要があります。これには、Java オブジェクトの割り当てが必要になる場合があります。また、JVM のヒープまたは非ヒープ メモリにデータが蓄積されている可能性もあります。

しかし、GC が実行された場合または実行されたときにスペースを再利用できる限り、それは実際には問題ではありません。できない場合は、JVM のバグまたは使用しているプロファイラーにバグが見つかった可能性があります。(ループを 1 つの非常に長いスリープに置き換えてみて、「リーク」がまだそこにあるかどうかを確認してください。) そして、これがプロファイリングによって引き起こされた遅いリークであるかどうかは、おそらく問題ではありません...通常は製品コードを実行しないためです。その長い間プロファイリングが有効になっています。


注: 呼び出しSystem.gc()によって GC が実行されるとは限りません。javadoc を読んでください。

于 2012-06-08T10:55:17.747 に答える
1

このコードにメモリ リークは見られません。Java のガベージ コレクターがどのように機能するか、およびその戦略を確認する必要があります。非常に基本的に言えば、特定の戦略で示されているように、GC は必要になるまでクリーンアップしません。

に電話してみるのもいいでしょうSystem.gc()

オブジェクトは、おそらく 2 つの Java コア関数で作成されます。

于 2012-06-08T10:56:25.017 に答える
0

これはプロファイラーのグラフからもわかるようにリークではないようです。グラフは、特定の間隔の後、つまり GC が実行されると急激に低下します。グラフが着実に上昇し続けていたら、リークしていたでしょう。その後に残っているヒープ領域は、thread.sleep() で使用する必要があります。また、(上記の回答の 1 つに記載されているように) プロファイラーのコードからも使用する必要があります。

にある VisualVM を実行し%JAVA_HOME%/binて、そこでアプリケーションを分析することができます。また、自由に GC を実行するオプションと、さらに多くのオプションが提供されます。

私が使用した VisualVM の機能が多ければ多いほど、メモリが消費されていました (最大 10MB)。したがって、この増加はプロファイラーからのものである必要がありますが、GC でスペースが再利用されるため、まだリークではありません。

于 2012-06-15T10:10:23.473 に答える
0

JVM のメモリ上限を非常に低く設定して、リークによってメモリが不足する可能性があることを確認してください。

使用済みメモリがその制限に達し、問題なく動作し続ける場合は、ガベージ コレクションが機能しています。

代わりに爆撃する場合は、本当の問題があります...

于 2012-06-08T11:38:12.000 に答える
0

これは、コンソールに表示されるテキストと、整数のサイズ (少し) によるものです。

Java 印刷関数は 8 ビット ASCII を使用するため、各文字が 8 バイトの場合、数値を 56000 印刷するとすぐにメモリが不足します。

于 2012-06-08T10:55:43.940 に答える
0

このチュートリアルに従ってメモリ リークを見つけてください: Analyzing Memory Leak in Java Applications using VisualVM . 最初にアプリケーションのスナップショットを作成し、しばらくしてから別のスナップショットを作成する必要があります。VisualVM を使用すると、これを実行してスナップショットと比較できます。

于 2012-06-08T10:56:37.763 に答える
-1

これはprintlnsなしで発生しますか? つまり、コンソールに printlns を表示し続けることがメモリを消費している可能性があります。

于 2012-06-08T10:53:01.900 に答える