Workaround für einen Java-Fehler, der einen Absturzspeicherauszug verursacht

8

Ein Programm, das ich entwickelt habe, stürzt die JVM gelegentlich aufgrund dieses Fehlers ab: Ссылка . Leider wurde der Fehler von Oracle nicht behoben und der Fehlerbericht besagt, dass keine Problemumgehungen bekannt sind.

Ich habe versucht, den Beispielcode aus dem Fehlerbericht durch Aufrufen von .register (sWatchService, eventKinds) im KeyWatcher-Thread zu ändern, indem ich alle ausstehenden Registrierungsanforderungen zu einer Liste hinzufüge, die ich im KeyWatcher-Thread durchlaufen habe, aber es ist stürzt immer noch ab. Ich vermute, das hatte genau den gleichen Effekt wie die Synchronisation auf sWatchService (wie der Übergeber des Fehlerberichts versucht).

Können Sie sich irgendeinen Weg vorstellen, um das zu umgehen?

    
Yrlec 25.04.2014, 16:15
quelle

3 Antworten

3

Ich habe es geschafft, einen Workaround zu erstellen, obwohl es etwas hässlich ist.

Der Fehler liegt in der JDK-Methode WindowsWatchKey.invalidate() , die den nativen Puffer freigibt, während die nachfolgenden Aufrufe weiterhin darauf zugreifen können. Dieses One-Liner behebt das Problem, indem es die Pufferbereinigung bis GC verzögert.

Hier ist ein kompilierter Patch für JDK. Fügen Sie das folgende Java-Befehlszeilenflag hinzu, um es anzuwenden:
-Xbootclasspath/p:jdk-8029516-patch.jar

Wenn das Patchen von JDK in Ihrem Fall keine Option ist, gibt es immer noch eine Problemumgehung auf Anwendungsebene. Es basiert auf der internen Windows WatchService-Implementierung.

%Vor%

Rufen Sie direkt nach der Registrierung des Schlüssels JDK_8029516.patch(watchKey) auf, und verhindert, dass watchKey.cancel() den nativen Puffer vorzeitig freigibt.

    
apangin 03.05.2014, 22:14
quelle
4

Von Kommentaren:

  

Es scheint, dass wir ein Problem mit der E / A-Löschung haben, wenn eine ausstehende ReadDirectoryChangesW aussteht.

Die Anweisung und der Beispielcode zeigen an, dass der Fehler ausgelöst wird, wenn:

  1. Es gibt ein ausstehendes Ereignis, das nicht konsumiert wurde (es ist möglicherweise nicht sichtbar für WatchService.poll() oder WatchService.take() )
  2. WatchKey.cancel() wird für den Schlüssel
  3. aufgerufen

Dies ist ein böser Fehler ohne universellen Workaround. Der Ansatz hängt von den Besonderheiten Ihrer Anwendung ab. Ziehen Sie in Erwägung, Uhren an einem einzigen Ort zu sammeln, damit Sie WatchKey.cancel() nicht aufrufen müssen. Wenn der Pool an einem Punkt zu groß wird, schließen Sie den gesamten WatchService und beginnen Sie erneut. Etwas Ähnliches wie.

%Vor%     
anttix 02.05.2014 19:12
quelle
3

Sie sind möglicherweise nicht in der Lage, das Problem selbst zu umgehen, aber Sie könnten mit dem Fehler umgehen und damit umgehen. Ich kenne Ihre spezifische Situation nicht, aber ich könnte mir vorstellen, dass das größte Problem der Absturz der gesamten JVM ist. Alles in einen try -Block zu setzen funktioniert nicht, weil Sie keinen JVM-Absturz abfangen können.

Wenn Sie nicht mehr über Ihr Projekt wissen, ist es schwierig, eine gute / akzeptable Lösung vorzuschlagen, aber vielleicht könnte dies eine Option sein: Führen Sie alle Dateien in einem separaten JVM-Prozess aus. Starten Sie von Ihrem Hauptprozess aus eine neue JVM (z. B. mit ProcessBuilder.start() ). Wenn der Prozess beendet wird (d. H., Die neu gestartete JVM stürzt ab), starten Sie sie neu. Natürlich müssen Sie in der Lage sein, sich zu erholen, d. H. Sie müssen im Auge behalten, welche Dateien Sie überwachen müssen, und Sie müssen diese Daten auch in Ihrem Hauptprozess behalten.

Jetzt besteht der größte verbleibende Teil darin, eine Kommunikation zwischen dem Hauptprozess und dem Dateiüberwachungsprozess zu implementieren. Dies könnte mit Hilfe von Eingabe / Ausgabe des Dateiüberwachungsprozesses oder mit Socket / ServerSocket oder ein anderer Mechanismus.

    
siegi 30.04.2014 20:45
quelle