call by value - Daten vom Heap entfernen ?

steveo6666

Grünschnabel
Also in der FH haben wir die Aufgabe einen binären Suchbaum mit rekursiven Methoden zu programmieren.
Wir sollen unter anderem eine Methode einbauen mit der alle Elemente gelöscht werden, wir sollen zeigen, dass die Elemente auch aus dem Heap verschwunden sind.
Die Elemente aus dem Stack zu entfernen ist eigentlich kein Problem.

private void destroyNode(Node N) {
/*
* Sets all nodes in subtree of N to null.
*/
if (N != null) {
destroyNode(N.left);
N.left = null;

destroyNode(N.right);
N.right = null;
}
}

public void destroy() {
/*
* Calls destroyNode for the tree.
*/
destroyNode(root);
root = null;
}

Aber wie lösche ich die Elemente aus dem Heap? Irgendwann werden sie vom Garbage Collector gelöscht, aber wir sollen sie selber entfernen.
Und wie zeige ich, dass die Elemente verschwunden sind?
 
Hallo,

Also wenn ich das richtig verstanden hab was die möchten, ist die einzige Möglichkeit die ich kenne, die Garbage Collection selbst auszuführen. Lasse mich aber gerne eines anderen belehren.
Mit
Code:
System.gc();
startest du die Garbage Collection.

MFG

zEriX
 
Zuletzt bearbeitet:
Hi,

System.gc() startet den GC möglicherweise. ;-) Aber das ist wohl nicht das Problem. Mit den Methoden Runtime.getRuntime().totalMemory() bzw Runtime.getRuntime().freeMemory() kannst Du den Speicherverbrauch feststellen und damit auch ob Deine Objekte entfernt wurden.

Am besten benutzt Du aber den HPROF Profiler von Java

http://java.sun.com/developer/technicalArticles/Programming/HPROF.html

Grüße

Jo

P.S. Mir fällt gerade noch ein: Starte die Anwendung mit java -verbose:gc Mainclass

Bewirkt, dass jedesmal eine Meldung ausgegeben wird, wenn der Garbage Collector aktiv wird.
 
Zuletzt bearbeitet:
Hi,

System.gc() startet den GC möglicherweise. ;-) Aber das ist wohl nicht das Problem. Mit den Methoden Runtime.getRuntime().totalMemory() bzw Runtime.getRuntime().freeMemory() kannst Du den Speicherverbrauch feststellen und damit auch ob Deine Objekte entfernt wurden.

Was für ein Speicherverbrauch wird denn da angegeben? Also ich häng im Moment dran, dass ich gern wissen würde, wieviel Speicher frei ist, aber Runtime.getRuntime().freeMemory() zeigt immer nur ca. 100 MB (von gesamt 1 GB) an, während die jconsole behauptet, es wären noch über 500 MB frei.
 
Hallo,

...
System.gc();

startest du die Garbage Collection.
Das stimmt nicht ganz... das gibt nur einen Hinweis an die JVM doch demnächst mal wieder
einen GC lauf zu starten. Es gibt jedoch keine Garantie, dass das auch tatsächlich gemacht wird.
Außerdem kann die JVM diesen Aufruf auch komplett ignorieren...

Wenn du sicher sehen möchtest, dass deine Instanzen GC'd wurden musst du entweder die finalize Methode
überschreiben und dort entsprechend loggen, oder mit einer ReferenceQueue arbeiten.

Java:
/**
 * 
 */
package de.tutorials;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author Thomas.Darimont
 * 
 */
public class ObjectGCNotificationExample {
	public static void main(String[] args) throws Exception {

		final ReferenceQueue<Garbage> garbageReferenceQueue = new ReferenceQueue<Garbage>();
		Executors.newSingleThreadExecutor().execute(
				createTracker(garbageReferenceQueue));
		
		Executors.newSingleThreadExecutor().execute(new Runnable(){
			@Override
			public void run() {
				List<PhantomReference<Garbage>> trashCan = new ArrayList<PhantomReference<Garbage>>();
				for (int i = 0; i < 20; i++) {
					Garbage garbage = new Garbage(new byte[2 << 10]);
					PhantomReference<Garbage> garbageTracker = new PhantomReference<Garbage>(
							garbage, garbageReferenceQueue);
					garbage = null;
					System.out.println("Created tracker: " + garbageTracker);
					trashCan.add(garbageTracker);
				}

				try {
					TimeUnit.SECONDS.sleep(5L);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				System.out.println("GC");
				for (int i = 0; i < 3; i++) {
					System.gc();
				}
				System.out.println("GC finished");
				
				try {
					TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
	}

	private static Runnable createTracker(
			final ReferenceQueue<Garbage> garbageReferenceQueue) {
		return new Runnable() {
			@Override
			public void run() {
				System.out.println("Tracking references");
				while (true) {
					try {
						System.out.println("Collected: "
								+ garbageReferenceQueue.remove());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};
	}

	static class Garbage {

		Object data;

		public Garbage(Object data) {
			this.data = data;
		}

// @Override
// protected void finalize() throws Throwable {
// System.out.println("Finalized: " + this);
// }
	}
}

Ausgabe:
Code:
Tracking references
Created tracker: java.lang.ref.PhantomReference@47b480
Created tracker: java.lang.ref.PhantomReference@19b49e6
Created tracker: java.lang.ref.PhantomReference@10d448
Created tracker: java.lang.ref.PhantomReference@e0e1c6
Created tracker: java.lang.ref.PhantomReference@6ca1c
Created tracker: java.lang.ref.PhantomReference@1bf216a
Created tracker: java.lang.ref.PhantomReference@12ac982
Created tracker: java.lang.ref.PhantomReference@1389e4
Created tracker: java.lang.ref.PhantomReference@c20e24
Created tracker: java.lang.ref.PhantomReference@2e7263
Created tracker: java.lang.ref.PhantomReference@157f0dc
Created tracker: java.lang.ref.PhantomReference@863399
Created tracker: java.lang.ref.PhantomReference@a59698
Created tracker: java.lang.ref.PhantomReference@141d683
Created tracker: java.lang.ref.PhantomReference@16a55fa
Created tracker: java.lang.ref.PhantomReference@32c41a
Created tracker: java.lang.ref.PhantomReference@e89b94
Created tracker: java.lang.ref.PhantomReference@13e205f
Created tracker: java.lang.ref.PhantomReference@1bf73fa
Created tracker: java.lang.ref.PhantomReference@5740bb
GC
GC finished
Collected: java.lang.ref.PhantomReference@47b480
Collected: java.lang.ref.PhantomReference@19b49e6
Collected: java.lang.ref.PhantomReference@10d448
Collected: java.lang.ref.PhantomReference@e0e1c6
Collected: java.lang.ref.PhantomReference@6ca1c
Collected: java.lang.ref.PhantomReference@1bf216a
Collected: java.lang.ref.PhantomReference@12ac982
Collected: java.lang.ref.PhantomReference@1389e4
Collected: java.lang.ref.PhantomReference@c20e24
Collected: java.lang.ref.PhantomReference@2e7263
Collected: java.lang.ref.PhantomReference@157f0dc
Collected: java.lang.ref.PhantomReference@863399
Collected: java.lang.ref.PhantomReference@a59698
Collected: java.lang.ref.PhantomReference@141d683
Collected: java.lang.ref.PhantomReference@16a55fa
Collected: java.lang.ref.PhantomReference@32c41a
Collected: java.lang.ref.PhantomReference@e89b94
Collected: java.lang.ref.PhantomReference@13e205f
Collected: java.lang.ref.PhantomReference@1bf73fa
Collected: java.lang.ref.PhantomReference@5740bb

Siehe auch hier:
http://www.tutorials.de/forum/algor...45228-speicherprobleme-den-griff-kriegen.html

Gruß Tom
 
@kulablec

http://java.sun.com/docs/books/performance/1st_edition/html/JPRAMFootprint.fm.html

@steveo666

um nachzuweisen, das die Objekte verschwinden, reicht ja auch ein Zähler, oder?

Mach doch eine statische Variable counter in der Nodeklasse, inkrementiere sie im Konstruktor und dekrementiere in protected void finalize(). (Destruktor). Wenn der GC anspringt ruft er die finalize-Methode auf, und Du hast den Nachweis, dass Die Objekte gelöscht sind, indem Du den Counter ausliest.

Gruß

Jo
 
Hallo,

wenn du wirklich nur wissen willst wieviele bzw. ob alle Instanzen wegeschaft wurden kannst du über einen statischen InstanceCounter machen (wie Ihn limago vorgeschlagen hat). Wenn du jedoch wirklich an dem Verschwinden einer konkreten Instanz interessiert bist bleibt nur der Ansatz über finalize und / oder ReferenceQueue

Wobei das überschreiben von finalize nicht unproblematisch ist. Objekte, die die finalize Methode von java.lang.Object überschreiben, werden vom GC anders behandelt als normale Objekte. Diese werden nämlich beim tatsächlichen GC zusätzlich in eine Queue (Queued for Finilization) reingestellt um den finalizer zu behandeln. Das verzögert das eigentliche wegräumen der Instanz durch den gc (und kann manchmal zu seltsamen Effekten führen...).

Gruß Tom
 
Mach doch eine statische Variable counter in der Nodeklasse, inkrementiere sie im Konstruktor und dekrementiere in protected void finalize(). (Destruktor). Wenn der GC anspringt ruft er die finalize-Methode auf, und Du hast den Nachweis, dass Die Objekte gelöscht sind, indem Du den Counter ausliest.

Auch eine sehr gute Idee! Aber es ist doch eher Zufall, dass der GC mal anspringt, wie Thomas sagte.
Über System.gc ist bei meinen bisherigen Versuchen die Objekte zu entfernen und count über den Constructor zu verringern, nichts passiert. Also count enthielt bisher immer den gleichen Wert. Es wäre Glück, wenn count mal 0 ausgeben würde.

Ich denke, dass meine bisherige Methode ausreichen wird. Hab mir gerade nochmal die Aufgabenstellung genau durchgelesen (leider auf Englisch :( ), dort steht:

You must show that your "destroy" method really simulates explicit disposal of nodes.

Also nicht, wie ich bisher annahm, dass ich zeigen soll, dass der Heap keine Node-Objekte mehr enthält.

Gruß steve
 
Zurück