Thread lancé le processus en cours d'exécution ne pourront pas détruire (Java)
Partir de plusieurs threads et que chaque exec() détruire() l'exécution d'un processus java en résulter des processus de destruction et de toujours courir après la sortie du programme. Voici un code permettant de reproduire le problème. J'ai remarqué le plus de threads que vous commencez, plus le processus de rester en vie. Et la plus de sommeil avant de les détruire(), moins les processus de rester en vie. (J'ai utilisé InfiniteLoop comme un exemple. Tout processus en cours d'exécution fera l'affaire.)
EDIT : le Bug a été signalé à Oracle, attendant une réponse. N'hésitez pas à partager toutes les connaissances/expériences sur le sujet.
for(int i = 0; i < 100; i++)
{
new Thread(new Runnable()
{
public void run()
{
try
{
Process p = Runtime.getRuntime().exec(new String[]{"java", "InfiniteLoop"});
Thread.sleep(1);
p.destroy();
}catch(IOException | InterruptedException e){e.printStackTrace();}
}
}).start();
}
Êtes-vous d'obtenir des exceptions?
Il n'y a pas d'exception.
Comment savez-vous?
e.printStackTrace() dans le bloc catch ne rien lors de l'exécution.
Vous êtes en attente pour les filets de résilier avant de sortir? Êtes-vous à la ponte d'un fil de démon (si oui, alors peut-être que la JVM est de mettre fin à l'intérieur de leur sommeil() l'appel lors de vos sorties de programme)?
Il n'y a pas d'exception.
Comment savez-vous?
e.printStackTrace() dans le bloc catch ne rien lors de l'exécution.
Vous êtes en attente pour les filets de résilier avant de sortir? Êtes-vous à la ponte d'un fil de démon (si oui, alors peut-être que la JVM est de mettre fin à l'intérieur de leur sommeil() l'appel lors de vos sorties de programme)?
OriginalL'auteur Bastien | 2013-08-07
Vous devez vous connecter pour publier un commentaire.
Si les sous-processus rien écrire sur stdout ou stderr (intentionnellement ou pas), ce qui pourrait causer des problèmes:
Source: http://www.javaworld.com/jw-12-2000/jw-1229-traps.html
L'ensemble de l'article est de l'OMI qui mérite d'être lu si vous avez besoin d'utiliser de l'Exécution.exec().
OriginalL'auteur Andrei Juan
Utiliser un
p.waitFor();
avantp.destroy();
,cela permettra d'assurer l'achèvement de la procédure précédente. Je pense que vous p.détruire commande est exécutée plus tôt que l'
exec()
de commande exécute l'action. Il devient donc inutile.p.waitFor()
attend la fin du processus, de sorte que dans le cas de laInfiniteLoop
, il ne retournera jamais. Leexec()
point -- je me demande; je ne peut rien trouver dans la documentation qui garantit que le processus a en fait été commencé quandexec()
renvoie, bien que je suppose qu'il a été, car il a la capacité, par exemple de générer des erreurs lors de la commande n'est pas trouvée.il ne marche pas attendre la fin du processus de retour? et puis p.détruire tue le processus..il réalise une création et le cycle de la destruction dans une itération..
p.waitFor() attend exec() pour retourner, par conséquent l'utilisation de ce comme un marqueur..vous pouvez vérifier whethr exec() fonctionne ou pas..
Voir docs.oracle.com/javase/7/docs/api/java/lang/...
OriginalL'auteur Abhishek
C'est tout simplement parce que, avant, les threads d'exécuter le détruire appel, votre programme principal se termine et tous les threads associés laissant les processus en cours d'exécution. Pour vérifier cela, il suffit d'ajouter un Système.sur appel après le détruire et vous trouverez qu'il n'est pas exécutée. Pour surmonter cette ajouter un Fil.le sommeil à la fin de votre méthode main et vous n'aurez pas le processus orphelins. La ci-dessous ne laisse pas de processus en cours d'exécution.
}
Je suis en cours d'exécution le code ci-dessus dans Debian et il n'a pas de processus à gauche après l'ajout de Fil.sleep(). Ce que j'ai fait ci-dessus n'est pas le bon moyen d'attendre pour les threads de s'arrêter. Vous devrez appeler Fil.rejoindre sur chacun des threads créés dans une boucle à la fin. Avez-vous essayé et est-il toujours le même problème?
Essayé votre code, le problème demeure. Mais je ne vois pas votre point de vue, le problème ne vient pas de fils, mais des processus. Un thread de fin n'est pas la fin du processus qu'il a lancé.
D'accord, les processus ne sont pas appelé à disparaître. Mais il y a deux raisons pour ne pas appelé à disparaître, il n'est pas appelé à disparaître en raison de détruire n'est pas appelé ou détruire lui-même a un bug. Pour éliminer le premier, je vous suggère de rejoindre le thread principal avec les threads, afin de vous assurer que les fils ont mis fin à ce qui élimine ce scénario. L'appel de "sommeil" méthode ne permet pas d'éliminer n'importe quel scénario.
De plus amples recherches montre les résultats suivants: sur Debian "jre construire 1.7.0-b147" / "jdk construire 1.6.0_31-b04" et sur windows 7 32 bits "java build 1.6.0_31-b04", les processus se termine correctement. Mais sur un windows 7 64 bits à l'aide d'un jdk construire 1.7.0-b147, les processus ne sont pas d'être résilié, même si les détruire est appelé.
OriginalL'auteur Raji
Vous devez fermer l'entrée/sortie/erreur de flux de processus. nous avons vu quelques problèmes dans le passé, la fourche n'a pas de remplir correctement à cause de ces flux n'étant pas fermé (même si elles n'ont pas été utilisés).
Cela ne devrait pas être nécessaire, si vous regardez, par exemple, à la mise en œuvre de
UnixProcess#destroy()
, il ferme tous les volets automatiquement.cette question a été répondu il y a 2 ans. vous êtes à la recherche d'une production de la version de java à partir de deux ans? (et cette expérience peut être à partir du début du jdk 6 ou même 5, difficile de garder tout droit à ce point dans le temps).
Bon, je regardais le JDK 7 pour être précis.
OriginalL'auteur jtahlborn
Je crois que, selon lien, un processus distinct est générée par le système d'exploitation en réponse à cet appel. Ce processus a une durée de vie de votre programme Java et fils au sein de sorte que vous pourrait s'attendre à continuer de courir après votre programme a quitté. Je l'ai juste essayé sur ma machine et il semble fonctionner comme prévu:
Bon point que j'ai oublié la détruire appel. Il serait utile d'ajouter un e.printStackTrace() à l'exception du bloc pour voir si des erreurs se produisent.
Il serait également utile d'ajouter quelques println des traces pour les fils pour voir si destroy() est réellement atteint.
Je l'ai essayé sur ma machine, juste maintenant, comme suit, avec pas de chance - je me demande si la JVM de l'instance sur le cas des OP de la machine a un problème.
Pourriez-vous essayer avec une infinie processus en boucle? Je ne l'expérience de la question avec la réalité de l'exécution de processus.
OriginalL'auteur Ali B
Ce n'est pas une réponse; je suis l'affichage complet de la source de ma propre tentative de recréer ce problème par la discussion en question vos commentaires.
Je ne peux pas reproduire ce problème sur Ubuntu 12.04; OpenJDK 6b_27 (voir cependant ci-dessous).
ProcessTest.java:
InfiniteLoop.java
Je ne peux pas reproduire le problème où les processus de fonctionnement restant après la JVM se termine. Cependant, si j'ajoute un long retard dans le thread principal après le démarrage du fils, mais avant de retourner à partir de main, je vois à peu près une douzaine d'exécution java processus qui collent autour (même si elles sont interrompues lorsque le programme principal se termine).
Mise à jour:
J'ai juste eu à sortir sur 5 les processus en cours d'exécution après la clôture. Il n'est pas toujours le cas. Bizarre. Je veux en savoir plus à propos de cette trop. J'ai un pressentiment qu'il a quelque chose à voir avec détruisant le processus trop rapidement ou une sorte de course à condition, peut-être java fourches quelque chose ou fait quelque chose pour créer un nouveau processus qui destroy() ne prend pas soin de si on l'appelle trop rapidement /au mauvais moment.
J'ai trouvé un vieux bug (mais il n'est pas marquer résolu), en indiquant que si un processus génère les sous-processus, ils ne peuvent pas être tués par destroy(). bugs.sun.com/bugdatabase/view_bug.do?bug_id=4770092 Quelle est la version du JDK sont vous utilisez.
Voici une autre référence à ce qui ressemble à un problème similaire: Java outil/méthode à la force de tuer un processus enfant Et je tiens à m'excuser si je ne l'ai ajouté de la confusion dans votre vie, je n'ai pas vraiment utiliser les Processus beaucoup et ne suis pas familier avec les bizarreries. Espérons que quelqu'un d'autre le fera étape dans une réponse définitive. Il me semble qu'il ne gère pas les sous-processus, et je suis en supposant java fourches quelque chose. C'est tout ce que j'ai.
Ubuntu ne fonctionne pas, vérifiez les commentaires que j'ai laissés dans votre question. Je suis en cours d'exécution dans la même question, au hasard.
Pourquoi ne pas modifier cela dans la question plutôt que de poster une réponse?
J'avais besoin d'un endroit pour poster mon code de test quand j'étais en va et vient avec l'OP. Je ne pense pas qu'il est approprié de le modifier dans quelqu'un d'autre question. Je vais enlever cette fois, c'est résolu. Je suis d'accord c'est pas l'idéal, mais il n'est pas prête bien à ces types de discussions. 🙂
essayez d'ajouter
p.getOutputStream().close(); p.getInputStream().close(); p.getErrorStream().close();
avant de les détruire appel.OriginalL'auteur Jason C
Il y a une condition de concurrence entre le moment de l'Exécution.exec coup d'envoi à un nouveau thread pour démarrer un Processus et quand vous dites que le processus s'auto-détruire.
Je suis sur une machine linux et je vais donc utiliser la UNIXProcess.class fichier pour illustrer.
Runtime.exec(...)
va créer un nouveauProcessBuilder
et le démarrer sur une machine unix crée un nouveauUNIXProcess
instance. Dans le constructeur deUNIXProcess
il y a ce bloc de code qui exécute le processus en arrière-plan (fourche) filetage:Avis que le thread d'arrière-plan définit le champ
pid
qui est de l'UNIX id de processus. Il sera utilisé pardestroy()
à dire le système d'exploitation qui processus pour tuer.Car il n'y a aucun moyen de s'assurer que ce thread d'arrière-plan est exécuté lorsque
destroy()
est appelé, on peut essayer de tuer le processus avant OU l'on peut essayer de tuer le processus avant pid champ a été défini; pid est initialisé et, par conséquent, est de 0. Donc, je pense que l'appel de détruire trop tôt va faire l'équivalent d'unkill -9 0
Il y a même un commentaire dans le UNIXProcess
destroy()
qui fait allusion à cela, mais ne considère que l'appel de détruire une fois que le processus a déjà fini, pas avant qu'elle ait commencé:Le champ pid n'est même pas marqué comme volatile, donc nous ne pouvons même pas voir la valeur la plus récente de tous les temps.
UNIXProcess
constructeur n'a pas retourné jusqu'à ce que après leforkAndExec
appel dans le thread se termine, c'est cegate
est pour. En fait, c'est comment il est capable de lever une exception si le processus ne parvient pas à démarrer, vous remarquerez que l'exception originaire de ce thread d'arrière-plan. Si le constructeur ne sera pas de retour jusqu'à ce que le processus est lancé, et par conséquent, il n'est pas possible d'appelerdestroy()
avant le processus de démarrage.Le commentaire que vous voyez dans
destroy()
est en se référant à un scénario différent. Ce commentaire fait référence au fait que si un processus meurt sur son propre, l'OS peut réutiliser son PID pour certains autres nouveaux processus, donc, le temps que nos appels d'applicationdestroy()
, le PID peut être un autre sans rapport avec le processus que nous ne voulons pas tuer. Le code de la près de que le commentaire juste dit "si le processus est déjà sorti sur son propre, de ne pas la tuer", qui est une tentative (pas fiable à 100%, comme l'a noté) pour éviter de tuer la mauvaise chose.OriginalL'auteur dkatzel
J'ai eu un problème similaire, et le problème avec
destroy()
pas de travail a été manifeste même avec un seul thread.Le processus n'a pas été détruit toujours si
TIMEOUT_MS
était trop faible. Ajout d'un autresleep()
avantdestroy()
fixe (même si je n'ai pas d'explication pourquoi):OriginalL'auteur Mifeet