Speicher freigeben



  • Hallo,
    ich habe hier eine kleines Testprogramm, welches ein extrem großes JLabel erzeugt und dieses in ein JPanel und dieses in ein JTabbedPane steckt. Dabei werden 55 MB Speicher verbraucht. Nachdem man den Tab aus dem JTabbedPane entfernt hat und auch das JPanel geleert und auf "null" gesetzt hat, werden aber immer noch 19 MB Speicher verbraucht. Was mache ich hier falsch, bzw. was muss ich tun, damit auch die restlichen 19 MB freigegeben werden?

    Der Garbage-Collector versucht es auf jeden Fall. Denn wenn ich die Zeile "System.gc()" auskommentiere, zeigt auch der dritte Speicher-Ausgabe-Aufruf noch 55 MB an.

    Vielen Dank und viele Grüße, Joe

    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTabbedPane;
    
    import de.raida.cad.netcad.gui.panel.CADPanel;
    
    import sun.awt.windows.ThemeReader;
    
    public class MemoryLeakTest {
    	private static void printMemoryUsage(String message){
    		long memoryMaximum = Runtime.getRuntime().maxMemory();
    		long memoryTotal = Runtime.getRuntime().totalMemory();
    		long memoryUsed = memoryTotal - Runtime.getRuntime().freeMemory();
    		System.out.println(message + ": " + (memoryUsed >> 20) + " / " + (memoryTotal >> 20) + " / " + (memoryMaximum >> 20) + " MB");
    	}
    
    	public static void main(String[] arguments){
    		printMemoryUsage("Before filling memory");
    
    		JPanel panel = new JPanel();
    		StringBuffer stringBuffer = new StringBuffer();
    		for(int i = 0; i < 10000000; i++)
    			stringBuffer.append("x");
    		panel.add(new JLabel(stringBuffer.toString()));
    		JTabbedPane tabbedPane = new JTabbedPane();
    		tabbedPane.addTab("Test", panel);
    		printMemoryUsage("After filling memory");
    
    		tabbedPane.remove(0);
    		panel.removeAll();
    		panel = null;
    		System.gc();
    		try {
    			Thread.sleep(5000);
    		} catch(Exception exception){
    			exception.printStackTrace();
    		}
            printMemoryUsage("After garbage collection");
    	}
    }
    

    Konsolenausgabe:

    Before filling memory: 0 / 4 / 63 MB
    After filling memory: 55 / 63 / 63 MB
    After garbage collection: 19 / 63 / 63 MB
    


  • Du setzt die Variablen, die du zum erzeugen des Panels benutzt nicht auf null. Zum Beispiel existiert stringBuffer weiter, was wohl das meiste der 19 mb ausmachen wird.



  • Aber auch wenn ich ...

    stringBuffer = null;
    

    ... einfüge nud das JLabel ebenfalls einzeln erzeuge und auf "null" setze, werden die 19 MB nicht freigegeben.

    Wenn ich nur den StringBuffer erzeuge und auf "null" setze, werden die 19 MB wieder freigegeben. Sobald ich den StringBuffer allerdings irgendwo einfüge, bekomme ich sie nicht mehr frei.



  • Gast-2009-04-12 schrieb:

    Sobald ich den StringBuffer allerdings irgendwo einfüge, bekomme ich sie nicht mehr frei.

    Dann wird der Inhalt ja auch noch irgendwo referenziert.
    Wo ist das Problem?



  • Solange in Java auf ein Objekt noch eine Referenz zeigt, wird sein Speicher nicht freigegeben. Da du den Inhalt des StringBuffers irgendwo einfügst, wird von dort eine zweite Referenz auf den StringBuffer erzeugt. Wenn du dann folgendes machst:

    stringBuffer = null;
    

    gibt es ja immer noch diese zweite Referenz auf den StringBuffer, d.h sein Speicher wird immer noch nicht freigegeben.



  • Vielen Dank. Wenn ich das JLabel einzeln instanziiere und vor dem GC label.setText(null) aufrufe, wird der Speicher komlett freigegeben.

    Was ich aber nicht verstehe: Wenn ich alle Objekte auf "null" setze, warum beachtet der GC noch Referenzen von auf "null" gesetzen Objekten? Die könnte er doch eigentlich ignorieren, oder?



  • Gast-2009-04-12 schrieb:

    Was ich aber nicht verstehe: Wenn ich alle Objekte auf "null" setze, warum beachtet der GC noch Referenzen von auf "null" gesetzen Objekten? Die könnte er doch eigentlich ignorieren, oder?

    Du setzt referenzen auf null, nicht objekte.

    Wenn du 2 Referenzen auf ein Objekt hast, und eine Referenz auf null setzt, dann darf das objekt nicht gelöscht werden, da du ja noch eine referenz auf das objekt besitzt...


Anmelden zum Antworten