2015-02-09 24 views
21

Ich verwalte eine Bibliothek, die einen Daemon-Thread startet, um im Hintergrund zu arbeiten. In regulären Java- und Android-Anwendungen wird dieser Thread einmal gestartet und wird für die gesamte Lebensdauer des Prozesses ausgeführt. Es geht nie aus und das ist in Ordnung.Beenden eines Threads beim Entladen der App

Wenn meine Bibliothek in einem Anwendungscontainer enthalten ist, der das Entladen von Anwendungen unterstützt (z. B. Tomcat), wird die Anwendung nie entladen. Mein laufender Thread enthält starke Verweise auf seine eigene Klasse und verhindert, dass die gesamte Anwendung entladen wird. Benutzer meiner Bibliothek können ihre App nicht austauschen, ohne dass jedes Mal Speicher verloren geht.

Wie kann ich am besten benachrichtigt werden, wenn der Anwendungscontainer meine Bibliothek entladen möchte?

Dies ist eine kleine Bibliothek ohne Abhängigkeit von Anwendungscontainer-APIs. Es weiß nicht, in welchem ​​Anwendungscontainer es ausgeführt wird und es nicht möchte!

Die Tatsache, dass diese Bibliothek einen Thread startet, ist ein Implementierungsdetail. Endbenutzer der Bibliothek sollten nicht wissen müssen, dass ein Thread gestartet wird, und es liegt nicht in ihrer Verantwortung, sie herunterzufahren.

+0

Gibt es ein anderes Objekt, bei dem Sie die Garbage Collection erkennen könnten? – immibis

+0

Ich bin mir nicht sicher, ob ich dein Problem richtig verstehe, aber vielleicht ist das: https://weblogs.java.net/blog/kcpeppe/archive/2011/09/29/mysterious-phantom-reference hilfreich? –

Antwort

6

Können Sie nicht feststellen, ob Ihre lib in den letzten x Minuten/Sekunden von der Anwendung verwendet wurde, und den Thread herunterfahren, wenn nicht? Bei der nächsten Verwendung neu starten? Die java.util.concurrent.ThreadPoolExecutor funktioniert auf diese Weise.

+0

Dies kann funktionieren. Es ist bedauerlich, die Prozessräumung zu stoppen, aber nicht umsetzbar. –

2

Dies ist ein interessantes Problem. Eine Idee, die Sie ausprobieren möchten:

Lassen Sie den Daemon-Thread schwache Referenzen zu Ihrer Bibliothek verwenden. Dann haben Sie ein Schutzobjekt in der Bibliothek, dessen finalize() Methode den Daemon-Thread entfernt.

Würde so etwas funktionieren?

+0

Leider enthält die Bibliothek keine Referenzen zurück auf die Anwendung, so dass Ansatz für mich nicht funktioniert. –

+0

Jesse - Ah - Ich denke, dass ich mit meiner Verwendung des Begriffs "Anwendung" etwas Verwirrung verursacht haben könnte. Ich meinte deine Bibliothek. Ich bin mir ziemlich sicher, dass die beschriebene Strategie funktionieren wird. Ich werde den Text meiner Antwort ändern, um das deutlicher zu machen. –

+0

Der Garbage Collector kann nicht signalisieren, dass die App entladen wurde. Werte werden zu früh (vor dem Entladen) gesammelt; Klassen zu spät (nachdem mein Thread beendet wurde). –

7

Ihre beste Wette ist, eine Methode zur Verfügung zu stellen, die Bibliothek aufzuräumen. Der Endbenutzer muss sie aufrufen (vermutlich basierend auf der Handhabung des Anwendungslebenszyklus im Container). Sie könnten auch eine Listener für diese Fälle bereitstellen, wenn sie in einem kompatiblen Servlet-Container (z. B. Tomcat) verwendet wird, aber Ihr Endbenutzer muss dies trotzdem wissen und den Deskriptor in die Datei web.xml einfügen.

Die einzige andere Alternative besteht darin, dass Ihr Endbenutzer einen Listener erstellen muss, der den Thread zum Absturz bringt. Ich musste das mehrmals machen und es ist nicht schön. Es beinhaltet normalerweise die Verwendung von Reflektion, um den Thread zu erhalten und ihn zu töten. Natürlich wird die ThreadDeath-Ausnahme von einigen Bibliotheken gehandhabt und die Threads verweigern den Tod. Dies erfordert dann eine bedeutendere Verwendung von Reflexion, um das Chaos zu beseitigen.

Ihre Endbenutzer sind viel besser dran, wenn Sie ihnen eine einfache Möglichkeit geben, die Bibliothek aufzuräumen. Sie müssen wissen, dass Sie über Ihre Implementierungsdetails Bescheid wissen müssen, aber das tun sie bereits, weil Sie die App nicht entladen.

+0

Ich würde es vorziehen, dass zukünftige Benutzer meiner Bibliothek nicht feststellen müssen, dass ihre Apps nicht entladen werden und dann nach Fix suchen müssen. Viel besser, wenn es einfach funktioniert! –

+0

@JesseWilson Ich stimme völlig zu! Die Realität ist jedoch, dass es keine automatische und zuverlässige Möglichkeit gibt, zu erkennen, dass Sie in einer Webanwendung ausgeführt werden, ganz zu schweigen davon, wenn diese Anwendung entladen wird. Es ist besser, es dem Benutzer leicht zu machen, damit umzugehen, als es ein schmerzhaftes Problem zu lassen, um herumzuarbeiten. – Rob

+2

Vielleicht könnten Sie diese API (zur sofortigen Bereinigung durch informierte Verbraucher) anbieten, * sowie * eine Art automatisierter Timeout-basierter Ansatz wie @Cfx für (uninformierte Verbraucher) vorschlagen. – rewbs

1

Sie können ComponentCallbacks2.onTrimMemory() verwenden. Dies wird aufgerufen, wenn das System wenig Ressourcen hat und die App im Hintergrund Ressourcen freigeben sollte.

Meine Erfahrung ist, dass, wenn onTrimMemory (TRIM_MEMORY_COMPLETE) aufgerufen wird, dann die App kurz davor ist, getötet zu werden.

+0

Ich bin speziell an Fällen interessiert, in denen der Prozess weiterläuft, aber die Anwendung darin entladen ist. ComponentCallbacks werden nicht helfen, da Android keine Entladeklassen implementiert. –

Verwandte Themen