Seite 1 von 1

"Memory Leak" in DynamicArray

Verfasst: 20. Apr 2017 17:48
von GreenLightning
Ich würde gerne an die kurze Diskussion über das "Memory Leak" in der heutigen, zweiten Vorlesung anknüpfen (Link zu der entsprechenden Stelle der Vorlesungsaufzeichnung).

Ich bin der Meinung, dass man auch in Java sehr wohl Memory Leaks erzeugen kann. Wikipedia schreibt dazu (Link):
Falls die verwendete Laufzeitumgebung eine automatische Speicherbereinigung bereitstellt, versucht diese zu ermitteln, auf welche Speicherbereiche ein Prozess nicht mehr zugreift. Stellt die Laufzeitumgebung fest, dass ein belegter Speicherbereich für das Programm nicht mehr erreichbar ist, wird dieser wieder freigegeben. Nicht mehr erreichbar heißt in diesem Zusammenhang, dass keine gültige Referenz auf den belegten Speicherbereich mehr existiert. Speicherlecks können dabei dennoch entstehen, wenn der Speicher für das Programm noch erreichbar ist, d. h. es eine Referenz auf den Speicher hält, ihn aber dennoch nicht mehr verwendet.
Das ist genau der Fall, der hier auftritt: Logisch gesehen wurde das Objekt bereits aus unserem DynamicArray entfernt, trotzdem befindet sich in theArray noch eine nicht mehr benötigte Referenz (obsolete reference) auf das Objekt, die verhindert, dass der Garbage Collector seine Arbeit tut.

Je nach Größe der in dem Array gespeicherten Objekte kann dies fatale Auswirkungen auf die Performanz bzw. den Speicherverbrauch des Programms haben. Hier ein Beispiel dazu:

Code: Alles auswählen

public int scrapePage(String url) {
	List<String> interestingLinks = new ArrayList<>();

	DynamicArray<byte[]> caches = new DynamicArray<byte[]>(10);
	for (int i = 0; i < 10; i++) caches.insert(new byte[100_000_000], i);

	// ...
	// Sehr komplizierter Code, der die Webseite aufruft (und dafür
	// das Cache-Array benötigt) und die Liste mit Links befüllt.
	// ...

	for (int i = 10 - 1; i >= 0; i--) caches.remove(i);

	int score = 0;
	for (String link : interestingLinks)
		score += scrapePage(link);

	return score;
}
Der Code reserviert ca. 1 GB an Byte-Arrays als Cache in einem DynamicArray, macht etwas damit, und entfernt anschließend die Byte-Arrays wieder aus dem DynamicArray. Bevor die Methode zu Ende ist ruft sie sich jedoch rekursiv selbst wieder auf. Theoretisch sollte dieser Code mit etwas über 1 GB an Speicher auskommen (mit den entsprechenden GC-Pausen...). Mit der momentanen Implementierung braucht jeder rekursive Aufruf jedoch 1 GB an zusätzlichem Speicher, da das DynamikArray noch die besagten unbenötigten Referenzen enthält und der Garbage Collector den Speicher noch nicht wiederverwenden kann.

Um diese Probleme zu vermeiden, sorgen wir einfach dafür, dass alle Zellen von theArray mit einem Index >= currentNumberOfElements den Wert null enthalten:

Code: Alles auswählen

public void remove(int position) {
	for (int i = position; i < currentNumberOfElems - 1; i++)
		theArray[i] = theArray[i + 1];
	theArray[currentNumberOfElems - 1] = null;
	currentNumberOfElems--;
}
Genau dieses Problem wird auch in Effective Java (Second Edition) in Item 6 diskutiert (Link zu einer Online-Version des entsprechenden Kapitels).

Auch dort wird empfohlen "null out references once they become obsolete" und "whenever a class manages it own memory, the programmer should be alert for memory leaks". (Das ist hier in der Tat der Fall, da wir nur einen Teil des Array-Speichers benutzen.)

Re: "Memory Leak" in DynamicArray

Verfasst: 20. Apr 2017 19:24
von Prof. Karsten Weihe
GreenLightning hat geschrieben: Ich bin der Meinung, dass man auch in Java sehr wohl Memory Leaks erzeugen kann.
Ich auch. 8)

Ich meine mich zu erinnern, dass ich genau das auch im weiteren Fortgang der Diskussion in der heutigen Vorlesung angesprochen hatte. Mein Punkt war, dass die paar Referenzen, die in theArray[currentNumberOfElems] ... theArray[theArray.length-1] ungenutzt bis zum nächsten Überschreiben stehen bleiben, keine große Sache sind.

Natürlich kann man mit geeignetem Komponententyp "mit Gewalt" so große Objekte in den Komponenten bauen, dass die Memory Leaks ernsthaften Umfang erreichen. Aber dafür braucht man keinen DynamicArray, das geht auch schon mit einem gewöhnlichen Array, also kein spezifisches Problem von DynamicArray.

Ich habe den Eindruck, dass wir beide gar keinen Dissens haben, nur vielleicht aneinander vorbei diskutiert haben? :)

KW

Re: "Memory Leak" in DynamicArray

Verfasst: 22. Apr 2017 13:32
von midstar
Ich würde daran gerne anknüpfen, da die Methode in meinen Augen wirklich unsauber gelöst ist. Wie Sie selbst sagten, bestehen heutige Programme meist aus Millionen Lines of Codes, und gerade wenn mehrere Programmierer eines Projektes einen solchen Ansatz wählen, summiert sich der sinnloserweise verbrauchte Arbeitsspeicher ganz schnell auch mal auf.

Im Endeffekt würde das Aufrufen dieser Methode im schlechtesten Fall nie ein wirkliches Objekt löschen und das Array sogar unverändert lassen, wenn immer das letzte Element des Arrays gelöscht werden soll.

Das wäre meine Begründung die Methode remove( int position); aus der Vorlesung verändern zu wollen.

Wäre es Ihnen denn möglich eine bessere Alternative dazu anzugeben? Oder ist dies für die weitere Vorlesung irrelevant?

Re: "Memory Leak" in DynamicArray

Verfasst: 22. Apr 2017 19:28
von Prof. Karsten Weihe
midstar hat geschrieben: Das wäre meine Begründung die Methode remove( int position); aus der Vorlesung verändern zu wollen.
Ok, ok, ich habe jetzt eine Version 02 hochgeladen, in der eine neue Zeile in remove eingefügt ist, mit der die frei gewordene Arraykomponente auf null gesetzt wird. Nach meinem Verständnis ist das Problem damit gelöst.

KW