2016-10-18 2 views
3

Ich habe eine Java-Anwendung rund um die Uhr, es hat eine Verbindung zu einem MySQL-Server und eine TimerTask (läuft Akka). Ich laufe auf OutOfMemoryError nach einer Woche oder weniger der Operation und der Heap-Dump zeigt eine LinkedHashMap mit mehr als 4 Millionen Strings, sie haben eine GC-Wurzel von java.io.DeleteOnExitHook mit 800 MB Heap.Speicherleck auf DeleteOnExitHook

Alle Saiten sind so etwas wie /tmp/jar_cachexxxx.tmp

Dieses Problem wurde in zwei Maschinen mit OpenJDK Runtime Environment konsistent ist (Build 1.8.0_101-b13). Der JDBC-Treiber ist der, der auf Maven "mysql-connector-java" Version 5.1.38 zur Verfügung gestellt wird, und ich verwende den Verbindungspool BoneCP, Version 0.8.0.

Jeder hat eine Idee über dieses Leck?

Update - 5/12/16

Das Problem wurde gelöst, nachdem wir den Compiler für das Projekt geändert haben. Wir haben festgestellt, dass der Eclipse-JAR-Creator das einzige ist, was eine Beziehung zum JAR-Cache hat. Nachdem wir das Projekt mit Maven kompiliert hatten, war das Speicherleck verschwunden.

+0

Könnten Sie weitere Informationen geben, wie Sie den Zugriff auf die Datenbank und mit Akka? Rufen Sie Java.io.File.deleteOnExit() auf? Wie viele Strings hast du gesehen, die wie "/tmp/jar_cachexxxx.tmp" aussahen? Das könnte ein Ablenkungsmanöver sein. Selbst wenn es 1000s dieser Zeichenfolgen gibt, werden 800MB nicht berücksichtigt. Versuche nach anderen Saiten zu suchen. – joseph

+0

Wie haben Sie festgestellt, dass _all_ die Strings wie "/tmp/jar_cachexxxx.tmp" aussehen? 800MB bedeutet, dass Sie etwa 800MB/30Bytes = 26.666.666 Strings benötigen, die so aussehen. – joseph

Antwort

0

Etwas in Ihrer Anwendung verwendet File.deleteOnExit. Da Ihre Anwendung jedoch nie existiert, muss Java all diese Dateien im Auge behalten, da sie gelöscht werden müssen, wenn sie schließlich beendet werden (was nie der Fall ist). Ich empfehle Ihnen herauszufinden, welcher Teil Ihrer Anwendung dies mit dem Debugger tut und dann eine Alternative finden.

5

Dies ist ein langjähriger und gut bekannter Fehler, der Sun/Oracle viele Male im Laufe der Jahre gemeldet wurde. Die aktuelle Fehlernummer ist JDK-4872014.

Das Problem ist, dass jedes Mal, wenn Sie die delete-on-exit-API verwenden, die Datei in einem HashMap gespeichert wird. Da Ihr Code in einem Server mit langer Laufzeit nur selten absichtlich beendet wird, kann die Map unbegrenzt wachsen, wenn Sie dies mit vielen temporären Dateien tun.

Im Wesentlichen ist die API nicht mit Servern mit langer Laufzeit verwendbar, da sie nicht wirklich so verwendet werden soll. Wenn Sie diese Funktionalität benötigen, müssen Sie sie selbst implementieren und die Bereinigung nach einem Zeitplan durchführen. So können Sie herausfinden, welche Dateien gelöscht werden können.

+0

Das sollte nicht der Bug der JVM sein. Die JVM muss sich alle Dateien merken, die beim Beenden der Anwendung entfernt werden müssen. Ich bin überrascht, dass es immer noch ein offenes Problem ist. – joseph

+1

Sie haben wahrscheinlich Recht. Diese API ist nicht für Prozesse gedacht, die idealerweise niemals heruntergefahren werden. –

0

Es gibt auch einen Hinweis im Pfadnamen der Dateien: "/tmp/jar_cachexxxx.tmp".

Offenbar werden diese Dateien erstellt, wenn ein URLClassloader eine Remote-JAR-Datei herunterlädt und lädt. Wenn Sie Millionen dieser Strings haben, bedeutet das, dass Sie das viel zu oft tun.