2016-06-30 7 views
1

Ich bin ein wenig Anfänger, wenn es um JAVA-Anwendungen geht, aber ich war an der Entwicklung einer ziemlich komplexen JAVA (8) -App beteiligt, die Multithreading erfordert. Ich selbst und ein anderer Entwickler sind immer wieder auf ein Problem gestoßen, bei dem die App nach einiger Zeit nicht mehr genügend Arbeitsspeicher hat.JAVA Multi-Threading, Speicherleck, Garbage Collector

Zuerst gaben wir der Anwendung 64 GB Arbeitsspeicher, aber nach ein paar Stunden hatte es nicht mehr genügend Arbeitsspeicher, Absturz und Neustart. Nur um es wieder und wieder zu machen. Kontext; Die Anwendung nimmt Nachrichten von einem Nachrichtensystem (ActiveMQ) und aus dem Meta der Nachricht muss eine XML-Datei erstellen, indem verschiedene Datenquellen nach Werten aufgerufen werden. Es könnte buchstäblich Millionen von Nachrichten geben, die verarbeitet werden müssen, also haben wir ein Multi-Threading-System entwickelt, jeder Thread behandelt eine Nachricht - und gab der Anwendung 40 Threads.

Da jedoch der Nachrichtenspeicher weiterhin belegt ist, steigt der Gesamtspeicherverbrauch im Laufe der Zeit an. Ich habe das Gefühl, dass der Müllsammler von uns nicht richtig genutzt wird?

Also im Moment haben wir einen Elternteil thread:

(new Thread(new ReportMessageConsumer(config, ""))).start();

Dann im ReportMessageConsumer wir X Anzahl der Threads eingerichtet haben, so würde dies 40 in unserem aktuellen Setup sein. Das wäre also alles unter dieser einen Gruppe. Sobald der XML-Code erstellt wurde und die Threads erledigt sind, wie können wir den Thread effektiv beenden und den Garbage Collector erzwingen, um diesen Speicher freizugeben, sodass wir dann einen neuen sauberen Thread erstellen können, um eine andere Nachricht aufzunehmen?

+0

Ein Thread stirbt kurz nach seiner 'run()' Verfahren entweder Rückkehr oder eine Ausnahme ausgelöst. Wenn Ihr Code keinen Verweis auf das 'Thread'-Objekt beibehalten hat (und in Ihrem Beispiel wird eindeutig keins beibehalten), sollten das' Thread'-Objekt und alle Objekte, auf die der Thread-Stack verweist, sofort zum Wiederherstellen freigegeben werden durch den GC. –

+2

Verwenden Sie keine Threads direkt, wenn Sie eine beenden und eine andere starten möchten, um "eine andere Nachricht" zu verarbeiten: Verwenden Sie Executoren. –

+0

Was ist der genaue OutOfMemoryError, den Sie sehen? Ist es heap, stack, gc overhead, kann native Threads nicht erstellt werden? –

Antwort

3

Ich fühle mich wie der Müllsammler wird nicht von uns richtig verwendet?

Das ist nicht das Problem. Das Beste, was Sie tun können, ist, dass der GC seine Sache ohne jede Störung macht. Versuchen Sie nicht, den GC zum Ausführen zu zwingen. Es ist selten hilfreich und oft schlecht für die Leistung.

Das eigentliche Problem ist, dass Sie ein Speicherleck haben. Es kann passieren, weil Sie mehr und mehr Threads bekommen ... oder es könnte etwas anderes sein.

  1. Rewrite Sie Code, so dass es ein ExecutorService verwendet einen begrenzten Pool von Threads, und eine Warteschlange von Aufgaben auf diesen Threads ausgeführt werden, verwalten:

    würde ich folgendes empfehlen. Sehen Sie sich die Javadocs für ein einfaches Beispiel an.

    Es ist nichts wert, dass die Verwendung eines Threadpools die Leistung Ihrer Anwendung verbessert. Das Erstellen eines Threads (d. H. Thread.start()) ist in Java ziemlich teuer.

  2. Wenn das Ihr Leck nicht heilt, dann verwenden Sie ein Speicherprofil-Tool, um herauszufinden, wie/warum Ihre Anwendung Speicher verliert. Es gibt viele StackOverflow Q & A, wie man das macht.Zum Beispiel:

+0

Danke dafür, macht so etwas wie: 'executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool (maxThread); while (wahr) { if (executorService.getActiveCount()

+1

Ein Thread-Pool, wie der ExecutorService, sollte eine feste Anzahl von Threads haben, die von einer Warteschlange unterstützt wird. Wenn Sie dem Thread-Pool also 10 Threads zuweisen, wird es nie mehr Threads haben. Wenn jedoch alle Threads ausgelastet sind, wird die 'processMessage' für die spätere Ausführung in die Warteschlange gestellt. Mit anderen Worten, Sie brauchen sich nicht um 'getActiveCount' oder irgendeine Thread-Verwaltung zu kümmern. –

+0

Danke, das macht die Dinge einfacher! Also, wenn wir an diesem Punkt immer noch in Speicherlecks lief, ist es, weil etwas im ExecutorService noch im Speicher gespeichert wird? Ich denke, wenn wir am Ende jeder Nachricht, die verarbeitet wurde, ExecutorService.shutdown() aufrufen, sollte es alles mit GC leeren? –