Der RMI-Server wird eigenständig heruntergefahren

8

Ich schreibe eine Java-Client-Server-Anwendung, die RMI für die Kommunikation verwendet. Mein Problem ist, dass der RMI-Server aus irgendeinem Grund einfach ohne Ausnahme oder Fehler heruntergefahren wird. Ich benutze Netbeans und ich habe ein Profil ausgeführt, um die Threads zu sehen.

Sie können im angehängten Bild den Zeitpunkt sehen, an dem die Anwendung angeblich das Ende des GC Daemon und der RMI Reaper-Threads beendet hat. Jedoch, auch nachdem die Anwendung beendet wurde, läuft der RMI TCP Accept-1099-Thread noch. Der Teil, der mich noch mehr verwirrt, ist, dass nach dem Auftauchen der Informationsnachricht (Sie können es im Screenshot sehen) mir sagen, dass der Server gestoppt wurde, die Threads weiterhin im Diagramm aktualisiert werden, also versuchte ich erneut eine Verbindung mit dem Client herzustellen . Obwohl es fehlgeschlagen ist, kann ich einen neuen RMI-Thread erstellen (Verbindung 18).

Ich habe keine Ahnung, wie ich dieses Problem beheben kann, und ich kann nicht herausfinden, wie es möglich ist, dass die Anwendung beendet wird, wenn der RMI-Annahme-Thread noch läuft.

Update: Hier ist die Hauptmethode des Servers:

%Vor%     
rhobincu 16.09.2014, 15:37
quelle

2 Antworten

8

Sie sehen eine Interaktion der VM beim Beenden des letzten Nicht-Dämon-Threads, kombiniert mit dem HotSpot-Garbage Collection-Verhalten, dem RMI-Exportverhalten und dem Ausführen der JVM unter dem NetBeans-Profiler.

Der Hauptthread wird beendet, nachdem die Methode main() zurückgegeben wurde. Da Sie jedoch ein RMI-Serverobjekt exportiert haben, hält RMI die JVM am Leben, indem Sie den Thread "RMI Reaper" (Nicht-Daemon) ausführen, solange aktive exportierte Objekte vorhanden sind. RMI bestimmt, ob ein exportiertes Objekt "lebendig" ist, indem es in der Objekttabelle nur einen schwachen Verweis darauf hält.

Wenn Sie sich die Methode main() ansehen, wird Ihr RMI-Serverobjekt leider nur über lokale Variablen referenziert. Daher wird früher oder später Müll gesammelt, aber für die schwache Referenz in der RMI-Objekttabelle. Wenn das Objekt schwach erreichbar wird, exportiert der RMI Reaper es und beendet es. Da der RMI Reaper der letzte Nicht-Daemon-Thread ist, wird die JVM beendet.

Beachten Sie, dass die RMI-Registrierung speziell behandelt wird. Das Exportieren einer Registrierung wird eine JVM nicht am Leben erhalten.

Beachten Sie auch, dass das Setzen einer Endlosschleife am Ende der main() -Methode nicht unbedingt verhindert, dass das RMI-Serverobjekt nicht exportiert und gecodiert wird. Der Grund ist, dass Objekte GC unterliegen, wenn sie unerreichbar werden, und eine Referenz, die in einer lokalen Variablen einer aktiven Methode vorhanden ist, reicht nicht aus, um sie erreichbar zu machen. Siehe meine Antwort zu einer weiteren Frage zu diesem Thema. Natürlich wird das Einfügen einer Endlosschleife in main() verhindern, dass die JVM beendet wird, da sie den Hauptthread am Leben erhält und der Hauptthread kein Daemon-Thread ist.

Um zu verhindern, dass Ihr RMI-Server nicht exportiert wird, ist es normalerweise ausreichend, einen Verweis darauf in einem statischen Feld zu speichern.

Nun, warum bleibt die JVM, wenn sie unter dem Profiler läuft? Das ist nur ein Artefakt der Funktionsweise des Profilers. Der Profiler erkennt, dass der letzte Nicht-Daemon-Thread beendet wurde (andere als zusätzliche Threads, die im Namen des Profilers in der JVM ausgeführt werden). Dies ist der Zeitpunkt, an dem das Dialogfeld mit der Meldung "Die Anwendung wurde beendet ausgeführt" angezeigt wird. Es hält die JVM jedoch am Leben, so dass Sie weiterhin Daten daraus erhalten können. Dies hat den Nebeneffekt, dass alle Daemon-Threads am Leben erhalten bleiben. Sie haben eine Registrierung exportiert, sodass Port 1099 weiterhin überwacht wird. Wenn sich die JVM in diesem Status befindet, können Sie möglicherweise RMI-Objekte registrieren, wenn Sie dies versuchten. Ihr RMI-Server-Objekt wurde schon lange nicht mehr exportiert und GC'd, so dass Anfragen an es nicht funktioniert. Aus diesem Grund wurde die RMI-Verbindung immer noch akzeptiert, als sich die JVM in diesem Zustand befand.

Unter dem Strich stellen Sie sicher, dass Ihre RMI-Serverobjekte nicht gecodiert werden. Ein guter Weg, dies zu tun, ist sicherzustellen, dass sie von einem statischen Feld aus erreichbar sind.

    
Stuart Marks 16.09.2014, 22:53
quelle
-2

Dies ist ein häufiges Problem mit RMI. Sie müssen den Verweis auf Ihre Implementierung als Klassenfeld speichern, damit GC nicht angezeigt wird. Und Sie müssen diese Klasse (mit dem main ()) auch am Leben erhalten.

Ich benutze dies als eine nie endende keep alive:

%Vor%

Sie können alles tun, was Sie möchten, damit die Implementierung am Leben bleibt und die Klasse mit main () am Leben bleibt.

    
edharned 16.09.2014 17:45
quelle

Tags und Links