Exception D'interruption occasionnelle lors de l'abandon d'une application Swing

j'ai récemment mis à jour mon ordinateur vers un plus puissant, avec un quad-core hyperthreading processeur (i7), donc beaucoup de concurrence réelle disponible. Maintenant je suis occasionnellement obtenir l'erreur suivante en cessant ( System.exit(0) ) une application (avec une interface graphique Swing) que je développe:

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)

bien, étant donné que cela a commencé à se produire avec un matériel plus compatible, et cela a à voir avec les threads, et cela arrive parfois, c'est évidemment une sorte de calendrier chose. Mais le problème est que la trace de la pile est si courte. Tout ce que j'ai est la liste ci-dessus. Il n'inclut pas du tout mon propre code, donc il est assez difficile de deviner où se trouve le bogue.

quelqu'un A vécu quelque chose comme ça avant? Une idée pour commencer à le résoudre?

Edit: depuis l'abandon d'une application Swing avec System.exit(0) peut être" impur", mais je ne veux pas pour définir le cadre principal à EXIT_ON_CLOSE parce que je veux m'assurer qu'il n'y a rien de critique quand l'application quitte, j'ai ajouté un mécanisme pour qu'il exécute le cadre principal dispose() méthode avant d'appeler System.exit(0) . Donc ça devrait être assez propre maintenant, mais l'exception occasionnelle arrive toujours. Cela se produit après que le System.exit(0) a été appelé; dispose() fonctionne sans problème. C'est-à-dire qu'il doit provenir d'un crochet d'arrêt:

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

j'ai même essayé d'éliminer explicitement tous les Window s en faisant une boucle à travers Window.getWindows() array (il contient des Dialog s sans propriétaire et ainsi de suite), mais cela n'a fait aucune différence. Cette question semble avoir peu à voir avec la "propreté" (c.-à-d. libérer explicitement les ressources d'écran natives avant de cesser de fumer). C'est autre chose, mais quoi?

Edit 2: le réglage de l'opération de fermeture par défaut à EXIT_ON_CLOSE ne fait aucune différence. http://www.google.com/search?q=sun.java2d.Disposer.run (éliminateur.java: 125) trouve quelques rapports de bogues, donc peut-être que c'est bien un bogue dans L'implémentation Java2D de Sun. Je peux imaginer que des insectes comme celui-ci peuvent ne pas être fixés pendant longtemps, parce qu'ils sont assez inoffensifs dans la pratique; une exception d'un crochet d'arrêt blesse à peine quelqu'un d'autre. Étant donné que cela se produit dans une application GUI, l'exception n'est même pas remarquée à moins que le stderr soit dirigé vers une console ou un log.

27
demandé sur Joonas Pulakka 2010-05-20 16:03:06

17 réponses

votre éliminateur est bloqué dans un appel à remove() (suppression de la ressource native de la plate-forme suivante). Cela signifie que le thread de disposer (un thread de démon) n'est pas arrêté naturellement lorsque la VM sort (ce qui est normal puisque vous le terminez via le système).sortie.))(

vous avez un thread non-daemon dans votre application qui empêche la VM de sortir quand toutes vos fenêtres pivotantes ont été éliminées.

Solution : trouvez-le et faites-le sortir.

normalement une application swing sort gracieusement si toutes ses fenêtres swing ont été éliminées, par exemple, ce programme pop une fenêtre puis sortir une fois qu'il est fermé (tous sans appel au système.exit()):

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

vous pourriez également essayer de courir le collecteur d'ordures avant de sortir, juste pour le plaisir.

15
répondu Justin 2010-06-01 13:14:48

si vous utilisez l'application swing, appelez D'abord le système.gc() et ensuite appeler la méthode dispose (). Je pense que cela fonctionnera très bien.. J'ai aussi l'utiliser.

voudrait voter ceci mais j'ai besoin de plus de rep. Cette solution a fonctionné pour moi, bien que je ne puisse pas trouver d'explication et que mon collègue de travail dise aussi qu'elle n'a pas de sens.

j'ai 1.7 et une application swing que j'ai créé, elle lit dans un fichier, réarrange le contenu et puis les sorties vers un fichier. a une course et le bouton quitter. utilise L'API préférences, l'écrivain, le lecteur, et quelques autres choses. Lors de l'ouverture et la fermeture de l'application (sans System.gc() ) immédiatement seulement deux fois successivement retournera cette même Exception comme indiqué ci-dessus. mais avec System.gc() juste avant dispose() Je ne peux pas obtenir l'Exception pour lancer à nouveau.

4
répondu Colin Hilbert 2013-05-02 14:56:57
Système

.exit () n'est probablement pas le moyen le plus propre de fermer une application basée sur Swing

ne pouvez-vous pas définir votre image principale à EXIT_ON_CLOSE:

mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE )

alors mettez-le à invisible?

connexe Q ici; système.exit(0) en java

2
répondu tim_yates 2017-05-23 11:46:20

je me demande si elle n'est pas liée à ce bug:

Bug De Java 6489540

signifie essentiellement que si Java2D est utilisé lorsqu'un objet Héritablethreadlocal existe ou qu'un contexttclassloader personnalisé est présent, ils sont capturés et vivent éternellement causant des fuites de mémoire et peut-être ce genre de serrures bizarres.

si c'est le cas, une solution de contournement serait de déclencher une action Java2D sur le thread principal (c'est-à-dire immédiatement au début de l'application) de sorte que le jet D'élimination vit dans un environnement "squeky propre". Il est démarré par un initialiseur statique donc juste un chargement fictif d'une ressource java2d et le libérer serait suffisant pour obtenir un jet de dépossession qui ne s'accroche pas aux choses indésirables.

2
répondu Peter Tillemans 2010-05-27 21:40:17

je pense que j'ai trouvé d'où vient le bug !

quand vous avez une application java de base avec un sous-menu de sortie dans un menu de fichier... Il y a un raccourci pour activer l'Action de sortie...Ce raccourci doit faire un lien circulaire ou quelque chose comme ça...

il y a les solutions:

tout d'Abord, c'est facultative pour obtenir tous claire: Implémente cette Interface "WindowListener" depuis votre fenêtre principale.

à la construction de cette fenêtre principale faire ceci :

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

implémente les fonctions de l'interface:

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) {}

après cela, vous devrez faire attention à vos raccourcis ! Vous devrez supprimer L'Action du Menu Exit pour la gérer avec une action performée:

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
}

Je n'explique pas pourquoi mais ça marche pour moi... Je pense qu'il y a une sorte de référence circulaire... Espérer pour vous aider à. Te voir.

2
répondu TheTiger 2011-07-08 07:15:37

j'ai le même problème ( Java 6 ). J'ai remarqué une unknwon soleil.awt.image.ImageFetcher fil dans le débogueur. Je pense que ça vient de moi qui utilise des boutons avec des icônes. Le fil ImageFetcher disparaît après 2 secondes. Si le thread ImageFetcher n'exécute pas mon programme, il sort très bien.

2
répondu Ray Hulha 2011-11-14 01:18:51

on dirait que vous avez un thread qui n'est pas terminé quand vous quittez. Notamment, le thread est wait()ing, et cette méthode lance une exception interrompue si vous essayez d'arrêter le thread pendant qu'il est en cours d'exécution. Je mets toujours des fils de fond à exécuter en tant que démons, ce qui pourrait aussi bien aider.

je voudrais effectuer les opérations suivantes dans votre 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();
  }
});

en sortant manuellement de la boucle, vous permettez à la méthode wait de terminer (j'espère que vous n'êtes pas d'attente terriblement long, et vous? Si vous êtes, vous pourriez vouloir réexaminer comment vous utilisez vos threads) et puis obtenir un point dans votre code où il est sûr à briser-sûr parce que vous l'avez codé pour le faire - et puis le fil se terminera, laissant l'application se termine juste très bien.

mise à Jour Peut-être utilisez-vous le thread event dispatch de façon inappropriée quelque part, et il attend/travaille toujours pour vous quand vous essayez de quitter? Le fil régulateur doit faire le moins de travail possible, et doit transmettre tout ce qui est complexe à un autre fil aussi rapidement que possible. J'admets que je me plante un peu dans le noir, mais je suis enclin à penser que ce n'est pas un bug, surtout si l'on considère que vous avez commencé à le remarquer sur une machine plus puissante - ce qui, pour moi, crie "condition de course!"pas de bug de Java.

1
répondu dimo414 2010-06-01 18:00:09

il y a parfois des erreurs, mais cela semble bien fonctionner:

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);
}
1
répondu TheTiger 2011-07-07 14:25:23

j'ai eu le même problème, et j'ai découvert que j'avais juste un cadre caché à l'arrière-plan (j'avais mis sa visibilité à false). Si je l'ai fait en sorte d'appel .dispose () sur mon cadre caché et puis .dispose () sur mon ordinateur central Je n'avais pas besoin d'appeler le système.exit (0), l'application vient de se nettoyer et de s'arrêter. Mon code est Scala, mais l'idée est la même.

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(); }
}
1
répondu cessationoftime 2011-12-29 21:36:01

si vous utilisez le Swing App Framework , vous pouvez remplacer Application.exit() pour effectuer le nettoyage, ou ajouter un ExitListener aussi. Sinon, vous pouvez également ajouter un crochet d'arrêt, Runtime.getRuntime().addShutdownHook() à votre application.

0
répondu JRL 2010-05-28 13:59:18
Les Threads

en java ne se terminent que lorsque toutes les méthodes run() terminent l'exécution. Sinon, vous aurez toujours ces objets Thread extended dans VM messing around. Vous devez terminer tous les fils avant de quitter l'Application.

considérez aussi que lorsque vous créez votre jFrame vous lancez un Thread (CURRENT_THREAD I believe)

0
répondu pampanet 2010-05-28 18:36:58

j'ai eu une erreur similaire et d'une certaine manière cela a fonctionné pour moi:

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();
        }
    });
}
0
répondu rtfminc 2011-08-16 09:52:35

Essayez d'utiliser EventQueue.invokeLater () pour fermer votre Swing.

0
répondu masm 2012-11-06 18:53:53

Cela semble être un bug résolu en Java 1.7.

a configuré mon Eclipse pour l'exécuter en jdk 1.7 et l'erreur a disparu.

Yoav

0
répondu Yoav 2013-03-29 21:58:21

je viens de tomber sur cette erreur en utilisant des bases de données. Le problème était que la connexion à la base de données n'était pas fermée. J'ai résolu cela en utilisant le code suivant:

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

je jette juste ça pour d'autres personnes...

0
répondu gedr 2014-04-11 19:19:12

essayez ceci. Cela a fonctionné pour moi. J'étais en train de créer une instance JFileChooser qui n'a pas été réglée correctement après le système.exit(0) appel.

setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent ev) {                	
                dispose();
                System.exit(0);
                }
 });
0
répondu Alex 2014-11-11 10:13:28

si vous utilisez l'application swing, appelez D'abord le système.gc() et ensuite appeler la méthode dispose (). Je pense que cela fonctionnera très bien.. J'ai aussi l'utiliser.

-1
répondu amit 2012-05-03 13:08:49