28

(ジェパディスタイルの質問、この問題が発生したときに回答がオンラインであったらいいのにと思います)

Java 1.4を使用して、あるときはスレッドとして実行したいが、他のときは実行したくないメソッドがあります。そこで、それをThreadのサブクラスとして宣言し、必要に応じてstart()またはrun()を呼び出しました。

しかし、私のプログラムは時間の経過とともにメモリをリークすることがわかりました。私は何が間違っているのですか?

4

3 に答える 3

48

これはJava1.4の既知のバグです:http://bugs.sun.com/bugdatabase/view_bug.do; jsessionid = 5869e03fee226ffffffffc40d4fa881a86e3: WuuT?bug_id = 4533087

Java 1.5で修正されていますが、Sunは1.4で修正する予定はありません。

問題は、構築時にThread、内部スレッドテーブルの参照リストにaが追加されることです。start()メソッドが完了するまで、そのリストから削除されません。その参照がある限り、ガベージコレクションは行われません。

start()したがって、そのメソッドを確実に呼び出す場合を除いて、スレッドを作成しないでください。Threadオブジェクトのメソッドrun()を直接呼び出さないでください。

Runnableそれをコーディングするより良い方法は、サブクラスではなくインターフェースを実装することですThread。スレッドが必要ない場合は、

myRunnable.run();

スレッドが必要な場合:

Thread myThread = new Thread(myRunnable);
myThread.start();
于 2008-09-20T10:25:06.870 に答える
3

Thread またはそのサブクラスのインスタンスを構築すると、メモリ リークが発生するとは思えません。まず、Javadocs や Java 言語仕様で言及されているようなものは何もありません。次に、簡単なテストを実行したところ、メモリ リークがないことがわかりました (少なくとも、32 ビット x86 Linux 2.6 上の Sun の JDK 1.5.0_05 では)。

public final class Test {
  public static final void main(String[] params) throws Exception {
    final Runtime rt = Runtime.getRuntime();
    long i = 0;
    while(true) {
      new MyThread().run();
      i++;
      if ((i % 100) == 0) {
        System.out.println((i / 100) + ": " + (rt.freeMemory() / 1024 / 1024) + " " + (rt.totalMemory() / 1024 / 1024));
      }
    }
  }

  static class MyThread extends Thread {
    private final byte[] tmp = new byte[10 * 1024 * 1024];

    public void run() {
      System.out.print(".");
    }
  }
}

編集:上記のテストのアイデアを要約するだけです。Thread の MyThread サブクラスのすべてのインスタンスは、独自の 10 MB 配列を参照します。MyThread のインスタンスがガベージ コレクションされていない場合、JVM はすぐにメモリ不足になります。ただし、テスト コードを実行すると、これまでに構築された MyThreads の数に関係なく、JVM が少量の一定量のメモリを使用していることがわかります。これは、MyThread のインスタンスがガベージ コレクションされるためだと主張します。

于 2008-09-20T11:26:57.223 に答える
2

問題の核心に近づくことができるかどうかを見てみましょう。

プログラムを(たとえば)start()を使用して1000 x起動し、次にスレッドでrun()を使用して1000 x起動した場合、両方ともメモリを失いますか?その場合は、アルゴリズムをチェックする必要があります(つまり、Runnableで使用されるVectorsなどの外部オブジェクトをチェックする必要があります)。

上記のようなメモリリークがない場合は、JVMに関するスレッドの開始パラメータとメモリ使用量について調査する必要があります。

于 2008-09-20T10:26:17.507 に答える