3

現在、アプリケーションの 1 つで発生するメモリ リークを調査しています。さらに調査した結果、ほぼ 14 時間アイドル状態にある 2 つの単純な Java Swing アプリケーションのテストを思いつきました。どちらのアプリケーションも 30 個の JButton で構成されています。

最初のアプリケーションは、アクション リスナーに強い参照を使用しています。

jButton1.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent evt) {
           jButton1ActionPerformed(evt);
     }
});

2 番目のアプリケーションは、アクション リスナーに弱参照を使用しています。

jButton1.addActionListener(new WeakActionListener(new MyActionListener(), this.jButton1))

WeakActionListener の実装は次のとおりです。

public class WeakActionListener implements ActionListener {

    private WeakReference weakListenerReference;
    private Object source;


    public WeakActionListener(ActionListener listener, Object source) {
        this.weakListenerReference = new WeakReference(listener);
        this.source = source;
    }

    public void actionPerformed(ActionEvent actionEvent) {
        ActionListener actionListener = (ActionListener) this.weakListenerReference.get();
        if(actionListener == null) {
            this.removeListener();
        } else {
            actionListener.actionPerformed(actionEvent);
        }
    }

    private void removeListener() {
        try {
            Method method = source.getClass().getMethod("removeActionListener", new Class[] {ActionListener.class});
            method.invoke(source, new Object[] {this});
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }

}

JConsole を使用して両方のアプリケーションを 14 時間プロファイリングしました。その時間枠の間、アイドル状態のままにします。弱参照または強参照を使用する両方のアプリケーションで、時間の経過とともにメモリ ヒープの消費量が増加していることを示しています。

私の質問は、これは Java Swing API のバグですか? この種のメモリリークを解決するための他の選択肢は何ですか?

前もって感謝します!

4

1 に答える 1

2

JDKには実際には多くのメモリリークが含まれていますが、あなたが説明している状況はそれらの1つではありません. アプリがアイドル状態の場合でも、OS はそうではないため、メモリ消費量は膨大です。入力イベントがアプリに送信されることがあります。これらのイベントを処理するには、いくつかのメモリ割り当てが必要になるため、ヒープが大きくなります。また、収集する必要がないため、収集されない可能性があります。アプリにはヒープに十分な空きメモリがあるため、頻繁に GC を実行することはありません。

さらに、Java でのメモリ リーク分析に対して間違ったアプローチを使用しています。正しいものは次のようになります。

  1. メモリ リークを分析する機能を備えた単純なアプリを作成します。
  2. すべての手順を実行した後、メモリは GC の準備ができているはずです。GUI 関連のアプリの場合は、((SunToolkit)Toolkit.getDefaultToolkit()).realSync()すべての非同期呼び出しとイベントを処理する呼び出しを追加することをお勧めします。これは内部 API であるため、実際のアプリでは使用しないでください。ただし、このような実験的なアプリでは非常に便利です。
  3. その後、大きなオブジェクトを割り当てて OutOfMemoryError を発生させようとします。OOME Java をスローする前に、すべての空きオブジェクトが収集されることを確認できます。OOME の catch ブロックでは、単にアプリを終了します。System.exit(0);

ここで最も興味深い部分: でアプリを実行し-Xmx20Mて、ヒープと-Xrunhprof:format=b,file=<Path to output file>. したがって、アプリが終了すると、OutOfMemory が原因ですべての空きオブジェクトが GC され、hprof が残っているすべてのオブジェクトのヒープをダンプします。jhat などの利用可能なツールの 1 つまたは Eclipse のいくつかのツールを使用して、ヒープを分析できます。

于 2013-03-27T09:58:13.090 に答える