Memory Leak und der Garbage Collector

Status
Nicht offen für weitere Antworten.

Taneeda

Aktives Mitglied
Hallo alle zusammen :)

Derzeit arbeite ich bei der Avira GmbH in Tettnang an meiner Diplomarbeit. Für die Arbeit entwickle ich ein Programm zum automatisierten Testen mit Java. Ich wende mich an euch wegen eines Problemes, bei dem ich einfach nicht weiter komme.
Ich kenne Java zwar grundlegend vom Studium, aber wirklich damit zu tun habe ich erst seit ca. 4 Monaten, also seit meiner Diplomarbeit.

Das Problem bezieht sich auf den Garbage Collector und meine beschränkte Programmiererfahrung :)
Ich habe nun in den vergangen Monaten eine Anwendung entwickelt. Diese Anwendung erstellt ein Objekt, welches den Test ausführt (ganz grob). Nachdem der Test beendet ist, soll das erstellte Objekt gelöscht werden um nicht unnötigen Speicherplatz zu beanspruchen... und genau da liegt mein Problem, der Speicher wird nicht freigegeben!!!

Seit Wochen bin ich nun schon auf der Suche nach einer Lösung, doch weder Google noch sonst etwas hat mir bisher weitergeholfen...

wenn ich ein Object direkt erstelle (new Object()) dann wird dieses ausgeführt und danach sauber gelöscht, da ja keine Referenz auf das Objekt vorhanden ist...
wenn ich aber ein Objekt mit einer Referenz darauf erstelle, also Object x = new Object(), dann bleibt der Speicher allokiert und ich weiß einfach nicht, wie ich den Platz wieder freigeben kann...

hier ein Beispiel:
Code:
package mypackage;

import java.io.IOException;
import java.io.InputStream;

public class MemTest 
{
	public Boolean stop = false;
	private MemClass[] memArray = null;
	
	public void doAlloc(Integer num)
	{
		memArray = new MemClass[num];
		
		for(int i=0; i<num; i++)
		{
			memArray[i] = new MemClass();
		}
	}
	
	public void clear()
	{
		memArray = null;
	}
	
	public static void main(String[] args) 
	{
		MemTest mt = new MemTest();
		
		System.out.print("Please type your command started: ");
		
		byte[] buffer = new byte[80];
		String input = "";
		int read;
		
		while(!mt.stop)
		{
			try
			{		
				// read the characters
				InputStream is = System.in;
				if(is.available() != 0)
				{					
					read = System.in.read(buffer, 0, 80);
					input = new String(buffer, 0, read);
					
					if(input.equalsIgnoreCase("go" +
						System.getProperty("line.separator")))
					{
						mt.doAlloc(1000000);
					}
					else if(input.equalsIgnoreCase("clear" +
						System.getProperty("line.separator")))
					{
						mt.clear();
					}
					else if(input.equalsIgnoreCase("exit" +
						System.getProperty("line.separator")))
					{
						mt.stop = true;
					}
				}
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
}

Das Programm belegt zu Beginn ca. 28 MB im Speicher, nach der Ausführung (go) um die 66 MB... wird aber die Referenz auf das Array gelöscht (clear) dann bleibt der Speicherplatz weiterhin allokiert...

Wie bekomme ich diesen Platz wieder zurück, sprich wie kann man den Speicherplatz wieder freigeben? ist das überhaupt möglich? Gibt es Alternativen?

Bitte helft mir, ich komme wirklich nicht mehr weiter und bin schon am verzweifeln... am liebsten würd ich den PC ausm Fenster schmeißen :autsch:
 

@x.l

Bekanntes Mitglied
Taneeda hat gesagt.:
Das Programm belegt zu Beginn ca. 28 MB im Speicher, nach der Ausführung (go) um die 66 MB... wird aber die Referenz auf das Array gelöscht (clear) dann bleibt der Speicherplatz weiterhin allokiert...

Aber nach Ende des Programms, wird er doch wieder frei gegeben. Wann der GarbageCollector aufräumt, bleibt ihm überlassen. Du kannst allerdings den Aufruf des GC mit System#gc erzwingen.
 

Ebenius

Top Contributor
@x.l hat gesagt.:
Aber nach Ende des Programms, wird er doch wieder frei gegeben. Wann der GarbageCollector aufräumt, bleibt ihm überlassen. Du kannst allerdings den Aufruf des GC mit System#gc erzwingen.

Garbage collection lässt sich nicht erzwingen. System.gc() empfiehlt der VM, jetzt mal aufzuräumen, zwingt sie aber eben nicht. Siehe dazu API Doc: System.gc().

Grüße, Ebenius
 

paldawin

Mitglied
Obwohl der Aufruf System.gc() eher nur ein Vorschlag an den GC ist, das er mal nachschauen soll! Ob er dann aufräumt ist ihm überlassen.
 

Taneeda

Aktives Mitglied
das stimmt, wenn das Programm beendet wird, wird auch der Speicher freigegeben... es stellt sich nur die Frage, wie man das zur Laufzeit gewährleisten kann, sofern das überhaubt möglich ist...

der Hintergrund... mein Programm soll später einmal die Nacht über tausende von Test durchlaufen und wenn da der Speicher immer zugemüllt wird, is irgendwann Schluss und das wäre ja nicht so praktisch ^^
 

Wildcard

Top Contributor
Woher nimmst du deine Werte mit 28 und 66? Du musst unterscheiden zwischen dem Speicher den der Prozess allokiert und dem Speicher der aktuell im Heap belegt ist. Der Prozess gibt keinen Speicher mehr her, braucht ihn aber unter Umständen auch nicht.
 
M

maki

Gast
Taneeda hat gesagt.:
das stimmt, wenn das Programm beendet wird, wird auch der Speicher freigegeben... es stellt sich nur die Frage, wie man das zur Laufzeit gewährleisten kann, sofern das überhaubt möglich ist...

der Hintergrund... mein Programm soll später einmal die Nacht über tausende von Test durchlaufen und wenn da der Speicher immer zugemüllt wird, is irgendwann Schluss und das wäre ja nicht so praktisch ^^
Du solltest dein Programm unter realistischen Bedingungen testen.
 

Ebenius

Top Contributor
Mach doch einfach mal folgendes. Benenne Deine main() methode um in "main2". Dann lege diese Methode neu an:
Code:
public static void main(String[] ignoredArgs) {
  for(int i = 0; i < 5; i ++) {
    main2(ignoredArgs);
  }
}

Dann führst Du Dein Programm nochmal aus und machst den Test fünfmal hintereinander. Und Du wirst feststellen, dass der Speicherbedarf nicht gestiegen ist. Ich gehe davon aus, dass Du die Speichereinstellungen für die VM nicht geändert hast (ergo default -Xmx64M).

Hilft Dir das? Der Garbage Collector räumt oft nur auf, wenn er muss. Die Speicherfreigabe ist in Java nicht deterministisch. Es hängt von einigen Faktoren ab, mit wie viel Aufwand der Garbage Collector Speicher freizugeben versucht. Davon abgesehen (weiter oben erwähnt) ist der Speicher den der Prozess belegt nicht das selbe wie der Speicher den Dein Programm innerhalb der VM belegt. Letzteren kannst Du erfragen mit:

Code:
final Runtime rt = Runtime.getRuntime();
rt.freeMemory();
rt.totalMemory();
rt.maxMemory();

Allerdings unbedingt die API-Doc dazu lesen, die Methoden erwecken vom Namen etwas den falschen Eindruck.

Hoffe das hilft, Ebenius
 

Wildcard

Top Contributor
Ebenius hat gesagt.:
Die Speicherfreigabe ist in Java nicht deterministisch.
Warum nicht determinisitisch? Der GC folgt klaren Regeln. Auf jedem Objekt das er untersucht und das nicht mehr stark referenziert wird ruft er finalize auf, danach wird erneut geprüft und dann das Objekt entfernt.
 

Taneeda

Aktives Mitglied
also ich muss schon sagen, dass ich wirklich sehr beeindruckt bin von euch :)
hab es noch nie erlebt, dass einem so schnell und hilfreich geholfen wurde *TOP*

ich habe die Änderung am Code vorgenommen (ebenius), hast recht, der Speicher bleibt in etwa gleich... den Speicherverbrauch sehe ich mir mit Sysinternals ProcessExplorer an...

die runtime Methoden hab ich auch mal reingemacht... hier die Ausgabe.
Code:
0
Please type your command started: go
finished
exit
8366216 (freeMemory)
44511232 (totalMemory)
66650112 (maxMemory)
1
Please type your command started: go
finished
exit
8379936
44511232
66650112
2
Please type your command started: go
finished
exit
6334752
42442752
66650112
3
Please type your command started: go
finished
exit
23797696
59928576
66650112
4
Please type your command started: go
finished
exit
23783344
59928576
66650112

kann ich denn nun davon ausgehen, dass es sich hierbei um kein Problem handelt? Oder wie muss ich dies interpretieren?

Kann mir jemand ein paar links nennen, wo das mit dem GC genauer erklärt wird? Würde mich gerne näher informieren um dies auch wirklich zu verstehen...
 

Wildcard

Top Contributor
Der GC räumt in der Regel nur dann auf wenn dem System gerade langweilig ist, oder wenn es notwendig ist (zB der Prozess stößt an die mit Xmx angegebene Grenze für den heap).
Wie gesagt gibt der Prozess keine allokierten Bereiche mehr frei, du kannst den tatsächlichen heap Verbrauch also nicht mit den Standardtools von aussen messen.
 

FArt

Top Contributor
Tipp:
einzelne Tests (oder Testsuits) und deren Ressourcen sollten über einen eigenen ClassLoader geladen werden.

Das stellt einigermaßen sicher, dass zwischen diesen keine Seiteneffekte auftreten. Beispiel: Klasse A wird für Test 1 und Test 2 benötigt. Die Klasse wird für Test 1 geladen, für Test 2 nicht mehr... (statische) Initialisierungen finden nur beim ersten mal statt.

Außerdem können so leichter alle Ressourcen wieder freigegeben werden. Der Testcontainer instanziiert eine Testsuite. Diese besitzt einen eigenen ClassLoader für die Ressourcen des Tests. Wenn der Test durch ist, kann die Referenz auf die Suite vom Container gelöscht werden => die Suite, der ClassLoader mit all seinen Ressourcen (auch Klassen!) werden vom GC bei Bedarf abgeräumt.

Auch wenn es oft anders propagiert wird: die VM weiß am besten, wann collected werde sollte...
 

Wildcard

Top Contributor
Das ist zwar richtig, führt aber dann tatsächlich zu einem (kleinen) Memory leak. Lädt man eine Klasse mehrmals (was ja nur möglich ist wenn man den Classloader weg wirft), bleiben AFAIK immer Artefakte in der Permanent Generation zurück.
 

Ebenius

Top Contributor
Wildcard hat gesagt.:
Ebenius hat gesagt.:
Die Speicherfreigabe ist in Java nicht deterministisch.
Warum nicht determinisitisch? Der GC folgt klaren Regeln. Auf jedem Objekt das er untersucht und das nicht mehr stark referenziert wird ruft er finalize auf, danach wird erneut geprüft und dann das Objekt entfernt.

Weil nicht festgelegt ist wann eine Instanz zerstört wird. Es ist ausschließlich festgelegt, dass sie nie zerstört wird, solange noch harte Referenzen existieren. Es ist nicht einmal klar, ob eine Instanz jemals zerstört wird; das Programm kann sich zum Beispiel beenden, ohne dass finalize() aufgerufen wird.

Von einem deterministic garbage collector spricht man, wenn die Instanz genau beim Verlust der letzten Referenz zerstört würde. Wenn das folgende "assert" garantiert nie fehl schlagen würde, dann hättest Du deterministic garbage collection. Die Garantie gibts aber mit Java nicht:
Code:
WeakReference<String> ref;
{
  ref = new WeakReference<String>(new String("Hallo"));
}
assert ref.get() == null;

Details beispielsweise hier: Real-time Java, Part 4: Real-time garbage collection.

Noch Fragen? Ebenius
 

Ebenius

Top Contributor
Wildcard hat gesagt.:
Das ist zwar richtig, führt aber dann tatsächlich zu einem (kleinen) Memory leak. Lädt man eine Klasse mehrmals (was ja nur möglich ist wenn man den Classloader weg wirft), bleiben AFAIK immer Artefakte in der Permanent Generation zurück.

Das weiß ich zwar nicht genau, aber wenn Du damit Recht hättest, würde kein einziger Application Server funktionieren können. Oder doch?
 

Ebenius

Top Contributor
Taneeda hat gesagt.:
kann ich denn nun davon ausgehen, dass es sich hierbei um kein Problem handelt? Oder wie muss ich dies interpretieren?

Ich würde davon ausgehen.

Taneeda hat gesagt.:
Kann mir jemand ein paar links nennen, wo das mit dem GC genauer erklärt wird? Würde mich gerne näher informieren um dies auch wirklich zu verstehen...

Wahrscheinlich hilft das hier schon:

Grüße, Ebenius
 

Wildcard

Top Contributor
Ebenius hat gesagt.:
Das weiß ich zwar nicht genau, aber wenn Du damit Recht hättest, würde kein einziger Application Server funktionieren können. Oder doch?
Auszug aus http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
For most applications the permanent generation is not relevant to garbage collector performance. However, some applications dynamically generate and load many classes. For instance, some implementations of JSPTM pages do this. If necessary, the maximum permanent generation size can be increased with MaxPermSize.
Daher resultieren auch die von OSGi Frameworks berühmt berüchtigten Errors wenn die PermSize ausgeht.
 

Wildcard

Top Contributor
Ebenius hat gesagt.:
Von einem deterministic garbage collector spricht man, wenn die Instanz genau beim Verlust der letzten Referenz zerstört würde. Wenn das folgende "assert" garantiert nie fehl schlagen würde, dann hättest Du deterministic garbage collection.
Ich kenne in diesem Zusammenhang nur konservativ und nicht-konservativ.
Nicht-Deterministisch ist die Zeit die der Garbage Collector benötigt, aber im Bezug auf den Algorithmus dahinter habe ich diese Begrifflichkeit bisher noch nicht gelesen.
 

Ebenius

Top Contributor
Wildcard hat gesagt.:
Nicht-Deterministisch ist die Zeit die der Garbage Collector benötigt, aber im Bezug auf den Algorithmus dahinter habe ich diese Begrifflichkeit bisher noch nicht gelesen.

Vielleicht verwechsele ich den Ausdruck mit "deterministic finalization". Den gibt's zumindest im Zusammenhang mit dem disposable-Konzept in C#. :)
 

Taneeda

Aktives Mitglied
das war jetzt doch recht viel Input :)

ich danke euch vielmals, ihr habt mir enorm weiter geholfen, jetzt werd ich mich erstmal weiter mit dem GC beschäftigen... nochmals vielen Dank
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
B Image Matching in Memory Minigame Java Basics - Anfänger-Themen 7
B Memory Spiel Java Basics - Anfänger-Themen 29
J Memory-Spiel Aktivierung der Methode mit Timer Java Basics - Anfänger-Themen 44
Olis Erste Schritte Simples Memory Spiel möglich? Java Basics - Anfänger-Themen 1
Spencer Reid JavaFX Memory Thread.sleep Java Basics - Anfänger-Themen 1
T Art 4 Felder Matrix Memory Java Basics - Anfänger-Themen 2
V Memory Logik Problem/Denkblockade, bitte helft Java Basics - Anfänger-Themen 1
S Java memory fehler: Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap spa Java Basics - Anfänger-Themen 5
pinar memory spiel Java Basics - Anfänger-Themen 10
P NullPointerException in Memory-Spiel Java Basics - Anfänger-Themen 5
P Layout Manager - Welches Layout für Memory? Java Basics - Anfänger-Themen 7
A Java memory leakage Java Basics - Anfänger-Themen 9
T Out of Memory (Java Heap Space) Java Basics - Anfänger-Themen 9
S Datentypen Memory Problem Java Basics - Anfänger-Themen 12
I Memory-Spiel Feld nur einmal mischen Java Basics - Anfänger-Themen 2
O Memory Thread.sleep() Java Basics - Anfänger-Themen 5
K Memory-Spiel stecke Fest Java Basics - Anfänger-Themen 2
K Ein Memory Spiel ! Java Basics - Anfänger-Themen 6
K Memory-Spiel alle verdeckte karten aufdecken. Java Basics - Anfänger-Themen 26
A Memory Probleme beim Laden von thumbnails Java Basics - Anfänger-Themen 3
S memory heap problem Java Basics - Anfänger-Themen 9
J Memory Footprint von Objekten Java Basics - Anfänger-Themen 2
I Memory-Spiel Java Basics - Anfänger-Themen 2
W Servlet - out of memory Java Basics - Anfänger-Themen 7
G Memory-Spiel Java Basics - Anfänger-Themen 8
B Memory - Zufällige Anordnung von Buchstabenpaaren Java Basics - Anfänger-Themen 8
J Memory Java Basics - Anfänger-Themen 2
G Memory Projekt, Fragen über Fragen Java Basics - Anfänger-Themen 6
B Memory in Java Java Basics - Anfänger-Themen 16
T Out of Memory Error Java Basics - Anfänger-Themen 7
E Heapspace out of Memory Java Basics - Anfänger-Themen 8
Encera Garbage Collection Java Basics - Anfänger-Themen 9
T Variable in Schleife deklarieren, Speicherplatz, Garbage Collector Java Basics - Anfänger-Themen 10
H Frage zum Garbage Collector Java Basics - Anfänger-Themen 2
K Frage zum Garbage Collector Java Basics - Anfänger-Themen 5
T garbage collector Java Basics - Anfänger-Themen 2
S Vernichtung von objekten mit dem garbage collector Java Basics - Anfänger-Themen 14
I Problem mit garbage collector/Speicherfreigabe Java Basics - Anfänger-Themen 8
J Warum werden Threads nicht vom Garbage-Collector gelöscht? Java Basics - Anfänger-Themen 14
P Timer-Objekt und Garbage Collector Java Basics - Anfänger-Themen 6
P Garbage Collector beschleunigen Java Basics - Anfänger-Themen 25
U Garbage collector Java Basics - Anfänger-Themen 8
C Garbage Collector Java Basics - Anfänger-Themen 3
L-ectron-X Speicher freigeben - Garbage Collection Java Basics - Anfänger-Themen 6

Ähnliche Java Themen

Neue Themen


Oben