2016-07-25 7 views
0

Der folgende einfache Jersey Anruf Gegenstände in die Warteschlange Finalizer undicht: Jersey 2.x undichten Speicher (Finalizer) mit einfachen POST-Aufruf (Multithreaded)

public boolean startExperiment(Experiment experiment) { 
     final Client client = ClientBuilder.newClient(); 
     Response response = null; 
     RunDescriptor runDescr = experiment.getRunDescriptor(); 
     try { 
      final WebTarget webTarget = client.target(ExperimentController.getInstance().getRunnerUrl()).path("runs").path("startNewAsyncrun"); 
      response = webTarget.request().post(Entity.entity(runDescr, MediaType.APPLICATION_JSON)); 
      if (response != null && response.getStatusInfo().getStatusCode() != Status.CREATED.getStatusCode()) { 
       System.out.println("Error, Run not created! Response Info: " + response.getStatusInfo()); 
       return false; 
      } else { 
       return true; 
      } 
     } finally { 
      if(response != null) { 
       response.close(); 
      } 
      client.close(); 
     } 

    } 

Jersey versions with which I tested: 2.18, 2.20, 2.22.2, 2.23.1. The code is run from multiple threads (each thread running it once every minute, for example). Also closing Response and Client should not be necessary, added it jsut in case to test if it would help. Eclipse MAT shows Finalizer queue to be growing with Objects of type:

  • sun.security.ssl.SSLSocketImplementation
  • java.io.FileInputStream
  • sun.net.www.protocol.https.DelegateHttpsURLConnection
  • org.glassfish.jersey.client.ClientRuntime
  • ZipFileInflaterInputStream

Any help or thoughts on the matter is really appreciated!

+0

Sieht aus wie etwas, das Sie als ein Problem mit Trikot ablegen möchten. Nebenbei sei es empfohlen, 'Client'-Instanzen in einer Anwendung wiederzuverwenden, da sie teuer zu erstellen sind. –

Antwort

1

While I am not familiar with Eclipse MAT and what it is showing you, it is proper behavior for some objects to go through the Finalizer queue.

Under normal circumstances, any object that overrides the finalize Methode wird für Fertigstellung Warteschlange gestellt werden (die die finalize Methode des Aufrufs besteht). Die allgemeine Idee ist, dass, wenn der Garbage Collector ein Objekt als nicht erreichbar identifiziert, es sieht, ob die finalize Methode überschrieben wird und noch nicht aufgerufen wurde. Wenn finalize definiert ist und noch nicht aufgerufen wurde, wird das Objekt zur Finalisierung in die Warteschlange gestellt, andernfalls wird der Speicher gesammelt.

Der Finalizer scheint als eine Warteschlange implementiert zu werden, die von einem einzelnen Thread bedient wird. Der Thread verarbeitet jedes Objekt in der Warteschlange, indem er finalize aufruft. Nachdem der Aufruf an finalize abgeschlossen ist, wird das Objekt aus der Warteschlange entfernt.

Wenn der Garbage Collector erneut feststellt, dass das Objekt nicht erreichbar ist, wird es feststellen, dass finalize überschrieben, aber bereits aufgerufen wurde. Das Mitglied wird gesammelt.

Beachten Sie, dass die Verwendung dieser Funktion die Sammlung von Müll verzögert. Und während es ein bequemer Weg ist, ein Objekt zu bereinigen, garantiert die JVM nicht, wann oder ob die Methode finalize aufgerufen wird.

Ein verwandtes Risiko ist "Finalizer Hunger." Sie erwähnen "wachsen", vielleicht ist dies ein Problem, dem Sie gegenüberstehen. Wenn Sie genug Müll erstellen, der abgeschlossen werden muss, und wenn diese Finalisierung zu lange dauert, können Sie tatsächlich nicht genügend Arbeitsspeicher haben, da die einzelne Finalizer-Warteschlange nicht mithalten kann. Es gibt eine Reihe von Möglichkeiten, um mit dieser Situation umzugehen:

  • Machen Sie die Ausführung von finalize abgeschlossen (Endlosschleifen sind schlecht) und schnell.
  • Synchronisation in finalize vermeiden.
  • Weisen Sie dem Finalizer-Thread die höchste Ausführungspriorität zu. Dies kann durch Erstellen einer Garbage-Instanz erreicht werden, die die Thread-Priorität im Finalizer ändert. Erstellen Sie eine dieser Methoden während der App-Initialisierung.
  • Wenn Sie Hunger leiden, verwenden Sie einen Thread-Dump, um zu sehen, woran der Finalizer-Thread arbeitet.

    +0

    Hey Rob, ich bin dankbar für dein Interesse an meinem Problem. Mir ist bekannt, wie Finalizer und GC in einer JVM arbeiten. Das Problem ist, dass die Objekte, die sich in der Finalizer-Warteschlange befinden, nicht meine sind und nicht direkt von mir erstellt werden, sondern durch Jersey. Ich folge einfach den Beispielen und Best Practices von Jersey in einer Multithread-Umgebung und es funktioniert nicht. Das Verhungern des Finalizer-Threads ist sehr wahrscheinlich nicht das Problem, da die CPU-Nutzung längere Zeit unter 100% bleibt und selbst die Threads mit der niedrigsten Priorität Ausführungszeit erhalten sollten. Trotzdem werde ich mehr darauf eingehen. Vielen Dank! –

    +0

    @YordanBoev Wie ich in der Antwort erwähnt habe, solltest du herausfinden, was der Finalizer-Thread macht. Eine Reihe von Thread-Dumps (oder pausiert diesen Thread im Debugger) und zu sehen, was dieser bestimmte Thread tut, ob es Fortschritte macht, beobachtet in der Regel das Ausführen einer bestimmten Klasse finalisieren Methode, warten auf eine Sperre, etc. – Rob