# Heap-Speicher wieder freigeben



## Bazinga (16. Nov 2011)

Ich möchte zu einem bestimmten Zeitpunkt in meinem Programm den Speicher des Attributs _data wieder freigeben. 
Dies soll durch den Aufruf einer der resetData-Methoden erreicht werden.


```
public Vector _data = new Vector();

public void fillData() {
	for (int i = 0; i < 50000; i++) {
		HashMap map = new HashMap();
		map.put("id", i);
		_data.add(map);
	}
}

public void resetData1(){
	_data.removeAllElements();
}

public void resetData2(){
	_data.clear();
}

public void resetData3(){
	_data = null;
}

public void resetData4(){
	_data = new Vector();
}
```

1. Wenn ich mir in meiner Jboss-Konsole die Memory-Pools ansehe, bleibt der Tenured Gen unverändert. Warum wird der Speicher nicht freigegeben? Muss ich noch ein System.gc() hinterherschicken?
2. Welche Methode zum Reset ist am sinnvollsten? Haben alle den gleichen Effekt? Was sind die Unterschiede im Bezug auf den Speicher?
3. Werden die HashMap-Objekte auch alle vom Speicher gelöscht oder müssen diese vorher noch per remove() geleert werden?
4. Fallen Euch noch andere Punkte an dem Code auf in Bezug auf Speicheroptimiertung, die man verbessern sollte?


----------



## Marco13 (16. Nov 2011)

Vorneweg: Man sollte nicht Vector verwenden, sondern List. Das _kann_ auch ein Vector sein, aber man sollte sich nur auf's List-Interface verlassen (ist allgemeingültiger). 

```
private List data = new Vector();
```
bzw. gleich mit Generics

```
private List<Map<String, Integer>> data = new Vector<Map<String, Integer>>();
```

Zum Speicher: FALLS das ganze wirklich nötig ist, sollte man am ehesten Variante 3 oder 4 verwenden. Ein System.gc sollte eigentlich NIE notwendig sein). Die beiden Varianten unterscheiden sich natürlich von ihrer Bedeutung her. Falls man Variante 3 verwendet, muss man bei fillData eben Am anfang
data = new Vector();
reinschreiben. 

removeAllElements und clear haben die gleiche Bedeutung, aber letzteres ist aus dem List-Interface und deswegen allgemeiner und besser. Trtozdem werden nur die Elemente entfernt. Die Internen Datenstrukturen (d.h. ein Array) bleiben weiterhin bestehen. Wenn data vorher 1000000 Elemente enthalten hat, existiert nach "clear" immernoch ein Array der Größe >1000000. Also ist es besser, "data" selbst auf null zu setzen.


----------



## SlaterB (16. Nov 2011)

Jsva-Programme geben einmal allokieren Speicher des Betriebssystems nicht mehr ab oder? weiß ich selber auch gar nicht,

innerhald des von Java verwalteten Heap könnte aufgeräumt werden, aber warum zwingend diese Arbeit machen?
solange die Objekte freigegeben sind können sie ruhig noch darum liegen, sie werden schon spätestens dann abgeräumt wenn Platz für anderes innerhalb des Java-Programms benötigt wird,
vor einem OutOfMemomyError


----------



## Noctarius (16. Nov 2011)

Nein die JVM gibt einmal allokierten Speicher nicht mehr an das OS zurück, da generell davon ausgegangen wird "wenn ein Programm den Speicher einmal gebraucht hat, wird es ihn wieder brauchen". Außerdem beugt das ein wenig der Fragmentierung vor.


----------



## Tobse (16. Nov 2011)

Wieso willst du den denn freigeben? Setz die Zeiger einfach auf null. Wenn der Speicherplatz gebraucht wird, kommt die Garbage Collection und nimmt ihn sich. Wenn er aber nicht gebraucht wird, kannst du dir den Rechenaufwand zum Freigeben sparen.


----------



## Noctarius (16. Nov 2011)

Ich versteh nicht diesen Tipp mit "auf Null setzen". Der kommt immer und immer wieder. Es ist Blödsinn und verwirrend für Anfänger / Umsteiger.

Ich kann in Java keine "Freigabe" erzwingen, auch nicht durch null setzen. Sonst kommt noch irgendwer auf die Idee, dass das hier den Speicher für den GC "freigibt":


```
public class Foo {
  private final List<Bar> bars = new ArrayList<Bar>();

  public Foo() {
    bars.add(new Bar());

    test();
  }

  publiv void test() {
    Bar bar = bars.get(0);
    bar = null;
  }
}
```

Weder wird in diesem Fall der Speicher freigegeben, noch kann der GC irgendwas machen, weil weiterhin eine Referenz existiert.
Die EINZIGE sauber Variante ist Variablen-Scope 'as small as possible' zu halten und auch dann muss man verstehen wann der GC eine Instanz wegwerfen darf und wann nicht, null setzen bringt eben nur bedingt etwas (und nur wenn man weiß wann).

PS: Java hat keine Zeiger sondern Referenzen!


----------



## SlaterB (16. Nov 2011)

nur weil von einem Auto die Räder festgebunden sein können, darf man nicht mehr behaupten dass man mit Gas geben vom Fleck kommt?

der Zweck des null-Setzens wurde hier denke ich klar vermittelt bzw. scheint Bazinga auch schon ziemlich klar zu sein,
die Variable geht auf null, das Objekt ist nicht mehr referenziert, GC oder sonstwer könnte aufräumen,

dass eine andere Referenz auf ein Objekt das verhindert ist sonnenklar, wo steht das in Frage?
ein simpler Zusammenhang, kann mich an kein Problem dahingehend im Forum erinnern..

> Variablen-Scope 'as small as possible'
ist natürlich schöner und 99% alle Benutzer haben auch nie Probleme mit Speicher, aber es gibt nunmal Spezialfälle von langlebigen Objekten, die einfach unnütze Daten am Leben halten (nicht zwingend in diesem Thema hier),
da ist null-Setzen genau der einzige korrekte Weg, fertig,
dass man überhaupt darüber nachdenkt zeigt doch eher schon ein Verständnis für Referenzen, für den Grund des Speicherproblems,
die Idee, dass = null übersetzt destroy() heißen könnte trotz anderer Referenzen erscheint mir abwegiger, glaube nicht dass das verbreitet ist


----------



## Marco13 (16. Nov 2011)

Ich füge, weil es auf zwei verschiedenen Ebenen (!) zu diesem Thema passt, mal die ArrayList#clear methode hier ein:

```
/**
     * Removes all of the elements from this list.  The list will
     * be empty after this call returns.
     */
    public void clear() {
	modCount++;

	// Let gc do its work
	for (int i = 0; i < size; i++)
	    elementData[i] = null;

	size = 0;
    }
```

Die Objekte werden auf 'null' gesetzt, damit der GC sie sich (eventuell!) holen kann - aber der Array ist und bleibt mit seiner vollen Größe bestehen!


----------



## Bazinga (16. Nov 2011)

Vielen Dank, durch eure Antworten konnte ich mein Problem nun lösen. Ich setze das Attribut einfach auf null und warte bis der Gc aufräumt.


----------



## Noctarius (16. Nov 2011)

SlaterB hat gesagt.:


> aber es gibt nunmal Spezialfälle von langlebigen Objekten, die einfach unnütze Daten am Leben halten (nicht zwingend in diesem Thema hier),



Richtig, du sagst es selber - Spezialfälle. Die Standardantwort auf "wie bekomme ich das Objekt weg" ist aber zu 99% immer "auf null setzen". In 99% der Fälle zeugt das aber von schlechtem Design, diese Spezialfälle eben ausgenommen (z.B. Cache).


----------



## SlaterB (16. Nov 2011)

> Die Standardantwort auf "wie bekomme ich das Objekt weg" 
weil diese Frage eben nur dann gestellt wird wenn es wirklich ein solche seltene Situation ist 
nein, keine Ahnung, müsste man an kontreten Problem-Foren-Themen klären


----------

