27

最近、クアッドコア ハイパースレッディング プロセッサ (i7) を搭載したより強力なコンピューターにコンピューターを更新したため、多くの実際の同時実行が可能になりました。現在、開発中のアプリケーション (Swing GUI を使用) を終了 () すると、次のエラーが発生することがありますSystem.exit(0)

Exception while removing reference: java.lang.InterruptedException
java.lang.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
        at sun.java2d.Disposer.run(Disposer.java:125)
        at java.lang.Thread.run(Thread.java:619)

ええと、それがより並行性に対応したハードウェアで発生し始め、スレッドに関係しており、時折発生することを考えると、明らかにある種のタイミングの問題です. しかし問題は、スタック トレースが非常に短いことです。私が持っているのは上記のリストだけです。私自身のコードはまったく含まれていないため、バグがどこにあるかを推測するのはやや困難です。

誰かが前にこのようなことを経験したことがありますか? それを解決する方法はありますか?

編集: Swingアプリケーションを終了するのSystem.exit(0)は「汚れている」かもしれないのでEXIT_ON_CLOSE、アプリケーションが終了したときに重大なことは何も起こらないようにしたいので、メインフレームをに設定したくないので、それが実行されるようにメカニズムを追加しましたdispose()を呼び出す前のメイン フレームのメソッドSystem.exit(0)。これでかなりきれいになったはずですが、時折例外が発生します。System.exit(0)が呼び出された後に発生します。dispose()問題なく動作します。つまり、シャットダウン フックから来ている必要があります。

mainFrame.dispose(); // No problem! After this returns, all visible GUI is gone.
// In fact, if there were no other threads around, the VM could terminate here.
System.exit(0); // Throws an InterruptedException from sun.java2d.Disposer.run

配列Windowをループしてすべての s を明示的に破棄しようとしましたが (所有者のないs などが含まれています)、違いはありませんでした。この問題は、「クリーンネス」(つまり、終了する前にネイティブの画面リソースを明示的に解放する) とはほとんど関係がないようです。それは別のものですが、何ですか?Window.getWindows()Dialog

編集2:デフォルトのクローズ操作を設定してEXIT_ON_CLOSEも違いはありません。http://www.google.com/search?q=sun.java2d.Disposer.run(Disposer.java:125)でいくつかのバグ レポートが見つかったため、これは Sun の Java2D 実装のバグである可能性があります。このようなバグは、実際にはほとんど無害であるため、長い間修正されない可能性があると想像できます。シャットダウン フックからの例外は、他の人を傷つけることはほとんどありません。stderrこれが GUI アプリで発生することを考えると、コンソールまたはログに送信されない限り、例外は認識されません。

4

17 に答える 17

16

ディスポーザは、remove()(次のプラットフォームのネイティブリソースを削除する)の呼び出しでブロックされます。これは、VMが終了するときにディスポーザスレッド(デーモンスレッド)が自然にシャットダウンされていないことを意味します(System.exit()を介して終了しているため、これを予期する必要があります)。

アプリケーションにデーモン以外のスレッドがあり、すべてのスイングウィンドウが破棄されたときにVMが終了しないようにしています。

解決策:それを見つけて終了させます。

通常、swingアプリケーションは、すべてのswingウィンドウが破棄された場合に正常に終了します。たとえば、このプログラムはウィンドウをポップし、閉じられると終了します(すべて、System.exit()を呼び出さずに)。

public static void main(String args[]) throws Exception {
    JFrame jf = new JFrame();
    jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    jf.setVisible(true);
}

キックのためだけに、終了する前にガベージコレクターを実行してみることもできます。

于 2010-06-01T13:14:48.337 に答える
5

swing アプリケーションを使用している場合は、まず System.gc() を呼び出してから、dispose() メソッドを呼び出します。私はそれがうまくいくと思います..私もこれを使用しています。

これに賛成票を投じたいのですが、もっと担当者が必要です。この解決策は私にとってはうまくいきましたが、理由の説明が見つからず、同僚も意味がないと言っています。

私は1.7と私が作成したswingアプリを持っています。ファイルを読み込み、内容を再配置してからファイルに出力します。実行と終了ボタンがあります。プリファレンス API、ライター、リーダー、およびその他のいくつかを使用します。アプリを ( なしでSystem.gc()) 開いてすぐに閉じると、上記と同じ例外が 2 回連続して返されます。しかし、System.gc()直前dispose()に例外を再度スローすることはできません。

于 2013-05-02T14:41:15.673 に答える
2

System.exit() はおそらく、Swing ベースのアプリを終了する最もクリーンな方法ではありません

メイン フレームを EXIT_ON_CLOSE に設定できませんか:

mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE )

次に、非表示に設定しますか?

関連Qはこちら; Java の System.exit(0)

于 2010-05-20T12:11:53.557 に答える
2

このバグとは関係ないのだろうか:

Java バグ 6489540

基本的には、InheritableThreadLocal オブジェクトが存在するか、カスタム contextClassLoader が存在するときに Java2D が使用されると、それらがキャプチャされて永久に存続し、メモリ リークや、この種の奇妙なロックが発生する可能性があることを意味します。

この場合の回避策は、メイン スレッドで Java2D アクションをトリガーすることです (つまり、アプリケーションの開始直後)。これにより、DisposerThread は「クリーンな」環境に置かれます。これは静的イニシャライザによって開始されるため、java2d リソースのダミー ロードとそれを解放するだけで、望ましくないものに固執しない DisposerThread を取得できます。

于 2010-05-27T16:40:59.187 に答える
2

私は同じ問題を抱えています( Java 6 )。デバッガーに不明な sun.awt.image.ImageFetcher スレッドがあることに気付きました。アイコン付きのJButtonを使用していることに由来すると思います。ImageFetcher スレッドは 2 秒後に消えます。ImageFetcher スレッドが実行されていない場合、プログラムは問題なく終了します。

于 2011-11-14T01:18:51.240 に答える
2

私はバグがどこから来たのかを見つけたと思います!

ファイルメニューへの終了サブメニューを備えた基本的なJavaアプリケーションがある場合...終了アクションをアクティブにするショートカットがあります...このショートカットは循環リンクまたはそのようなものを作成する必要があります...

解決策があります:

まず第一に、これはすべてを明確にするためにオプションです。メインウィンドウからこのインターフェース「WindowListener」を実装します。

このメイン ウィンドウの構築時に、次の操作を行います。

JFrame frame=this.getFrame();
if(frame!=null)
{
   Window[] windows=frame.getWindows();
   for(Window window : windows)
   window.addWindowListener(this);
}

インターフェイスから関数を実装します:

public void windowOpened(WindowEvent e) {}

public void windowClosing(WindowEvent e) {
    JFrame frame=this.getFrame();
    if(frame!=null)
    {
        Window[] windows=frame.getOwnedWindows();
        for(Window window : windows)
        {
            window.removeWindowListener(this);
            window.dispose();
        }
    }
    //clear();
    System.gc();
}

public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}

その後、ショートカットに注意する必要があります。actionPerformed で管理するには、終了メニューからアクションを削除する必要があります。

private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
    //this.clear();
    svExitMenuItem.removeActionListener(null);//this call removes the end error from this way to exit.
    javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(etscampide.ETScampIDEApp.class).getContext().getActionMap(ETScampIDEView.class, this);
    actionMap.get("quit").actionPerformed(null);//null to avoid end error too
}

理由は説明しませんが、私にとってはうまくいきます...循環参照のようなものがあると思います...お役に立てば幸いです。じゃあ。

于 2011-07-07T14:18:12.330 に答える
1

時々エラーが再び発生しますが、これはうまくいくようです:

private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
    svExitMenuItem.removeActionListener(null);
    windowClosing(null);//i add it to clear and call the garbadge collector...
    javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(etscampide.ETScampIDEApp.class).getContext().getActionMap(ETScampIDEView.class, this);
    actionMap.get("quit").actionPerformed(null);
}
于 2011-07-07T14:25:23.533 に答える
1

私は同じ問題を抱えていて、背景にフレームが隠れていることがわかりました(可視性をfalseに設定しました)。隠しフレームで .dispose() を呼び出してから、メインフレームで .dispose() を呼び出した場合、System.exit(0) を呼び出す必要はなく、アプリケーションは自分自身をクリーンアップしてシャットダウンしました。私のコードは Scala ですが、考え方は同じです。

def top = new MainFrame {

   import javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE
   peer.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE)
   override def closeOperation() { endExecution; PreviewFrame.dispose(); this.dispose(); }
}
于 2011-12-29T21:36:01.193 に答える
1

終了時に終了していないスレッドが実行されているようです。特に、スレッドは wait() を実行しており、実行中にスレッドを停止しようとすると、そのメソッドは中断された例外をスローします。私は常にバックグラウンド スレッドをデーモンとして実行するように設定していますが、これも役立つかもしれません。

私はあなたのJFrameで次のことを行います:

myJFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
  public void windowClosing(WindowEvent we) {
    // Some pieces of code to instruct any running threads, possibly including
    // this one, to break out of their loops

    // Use this instead of System.exit(0) - as long as other threads are daemons,
    // and you dispose of all windows, the JVM should terminate.
    dispose();
  }
});

手動でループから抜け出すことで、wait メソッドを終了させ (それほど長く待機していないことを願っています。待機している場合は、スレッドの使用方法を再検討することをお勧めします)、次に取得します。ブレークしても安全なコード内のポイント (そうするようにコード化したので安全です) に達すると、スレッドが終了し、アプリケーションが正常に終了します。

更新 おそらく、どこかでイベント ディスパッチ スレッドを不適切に使用しており、終了しようとしても待機中または動作している可能性がありますか? ディスパッチャ スレッドは、できる限り作業を少なくし、複雑なものをできるだけ早く別のスレッドに渡す必要があります。私は少し暗闇の中で突き刺していることを認めますが、特にあなたがより強力なマシンでそれに気づき始めたことを考えると、それはバグではないと思う傾向があります. Java のバグではありません。

于 2010-05-28T17:42:28.660 に答える
0

EventQueue.invokeLater()を使用してSwingを閉じてみてください。

于 2012-11-06T18:53:53.797 に答える
0

Java のスレッドは、すべての run() メソッドの実行が終了したときにのみ終了します。そうしないと、VM でこれらの Thread 拡張オブジェクトが常にいじられます。アプリケーションを終了する前に、すべてのスレッドを終了する必要があります。

また、jFrame を作成するときにスレッドを開始していることも考慮してください (CURRENT_THREAD だと思います)。

于 2010-05-28T18:36:58.493 に答える
0

Swing App Frameworkを使用していた場合は、オーバーライドApplication.exit()してクリーンアップを実行するか、 を追加することもできますExitListener。それ以外の場合は、アプリにシャットダウン フックを追加することもできRuntime.getRuntime().addShutdownHook()ます。

于 2010-05-28T13:59:18.497 に答える
0

これを試して。これは私にとってはうまくいきました。System.exit(0) 呼び出し後に適切に破棄されなかった JFileChooser インスタンスを作成していました。

setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent ev) {                	
                dispose();
                System.exit(0);
                }
 });

于 2014-11-11T10:13:28.277 に答える
0

これは、Java 1.7 で解決されたバグのようです。

jdk 1.7で実行するようにEclipseを構成すると、エラーはなくなりました。

ヨアヴ

于 2013-03-29T21:58:21.277 に答える
0

データベースを使用してこのエラーに遭遇しました。問題は、データベースへの接続が閉じられていなかったことです。次のコードを使用してこれを解決しました。

Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    });

これを他の人のためにそこに捨てるだけです...

于 2014-04-11T19:19:12.807 に答える
0

同様のエラーが発生していましたが、どういうわけかこれでうまくいきました:

private static void createAndShowGUI() {
  JFrame jf = new MyProgram();
  jf.setVisible(true);
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

        public void run() {
          createAndShowGUI();
        }
    });
}
于 2011-08-16T09:52:35.083 に答える
-1

swing アプリケーションを使用している場合は、まず System.gc() を呼び出してから、dispose() メソッドを呼び出します。私はそれがうまくいくと思います..私もこれを使用しています。

于 2012-05-03T13:08:49.817 に答える