Speicherfreigabe bei Java
-
Hallo,
wenn ich mir meine Java Programme anschaue kommt es mir immer so vor als ober der GC den Speicher nicht aufräumt.
Das veranlaste mich zu einem Test.
c++ mit MFC Programm -------------------- SetDlgItemText(IDC_CMDSTART, "...."); CString* str = new CString[12345678]; Sleep(10000); delete[] str; SetDlgItemText(IDC_CMDSTART, "&Start"); Java ---------------------------- import java.awt.*; import java.awt.event.*; import javax.swing.*; public class speicher { public static void main(String[] args) { JMyFrame a= new JMyFrame(); } } class JMyFrame extends JFrame implements ActionListener { JButton cmd = new JButton("Start"); JMyFrame() { cmd.addActionListener(this); this.getContentPane().add(cmd); setBounds(100,100,200,200); setVisible(true); } public void actionPerformed(ActionEvent ev) { System.out.println("..."); String str[] = new String[12345678]; try { Thread.sleep(10000); }catch(InterruptedException e) {} System.out.println("Start"); System.gc(); } }
Speicheranzeige im XP TaskManager
Vor dem "Start" drücken
Während des Sleeps
Nach dem SleepC++
Speicher | Virtueller
1,504 | 292
49,848 | 48,568
1,521 | 292Java
Speicher | Virtueller
11,400 | 10,624
59,796 | 59,060
59,836 | 74,332so warum wird der Speicher nicht freigegeben???
Selbst wenn ich das Programm eine ganze Weile laufen lasse wird der Speicher einfach nicht freigegeben.Kann mir das jemand erklären ???
-
Die Speicher-Anzeige des Taskmanagers muss nicht mit dem tatsächlich benötigten Speicher übereinstimmen. ... i.A. wird die Zahl, die da angezeigt wird, falsch sein.
...minimier das Fenster mal und mach es dann wieder groß. Der Taskmanager sollte dann einen anderen Speicherverbrauch anzeigen. (...bei mir macht er das zumindest!)
-
Vielleicht versteh ich das Programm nur nicht ... aber nach dem sleep existiert doch noch eine Referenz auf den String, also wird er nicht collectet. An der Stelle wo System.gc() aufgerufen wird genauso.
-
Das "sleep" sollte tatsächlich rausgenommen werden, da unnütz. Der GC kann erst aktiv werden, wenn actionPerformed verlassen wird, da erst da keine Referenz auf das Array mehr existiert.
...zudem: AFAIK wird der GC normalerweise aktiv, wenn neuer Speicher benötigt wird und der Heap voll ist. ...oder wenn System.gc() aufgerufen wird, wobei hier eine Aktivierung des GC nicht garantiert ist. Das wird von Sun nur "empfohlen".
EDIT: ...habe gerade gesehen, dass das sleep für etwas anderes gedacht ist. ...ist also doch nicht unnütz.
Bashar: Das sleep ist da, damit er Zeit hat, im Taskmanager den Speicherverbrauch mit dem Array abzulesen.
[ Dieser Beitrag wurde am 01.05.2003 um 19:40 Uhr von Gregor editiert. ]
-
Du kannst den Code in actionPerformed mal durch folgenden ersetzen:
[java]
Runtime runtime = Runtime.getRuntime();
System.out.println (runtime.totalMemory() - runtime.freeMemory());
String [] array = new String [12345678];
System.out.println (runtime.totalMemory() - runtime.freeMemory());
array = null;
System.gc();
System.out.println (runtime.totalMemory() - runtime.freeMemory());[/code]...und sag mal, was da rauskommt!
-
Ausgabe in der Konsole nach 3 Mal starten
957760
49975600
593128---------------
600656
49983672
592208---------------
599632
49930664
548008---------------
Anzeigen im TaskManager (etwa):
59000 | 62000
55000 | 57000
12000 | 11000 <-- hier ist er weg!!!@ Bashar war echt bescheuert von mir gc noch in der gleichen Methode aufzurufen.
OK Programm leicht verändert:
boolean b = false; public void actionPerformed(ActionEvent ev) { b = !b; if (b) { System.out.println("..."); String str[] = new String[12345678]; try { Thread.sleep(10000); }catch(InterruptedException e) {} System.out.println("Start"); } else { System.gc();System.gc();System.gc();System.gc();System.gc(); } }
Und siehe da! wenn ich einmal den gc aufrufe ist es das gleiche, aber mit den 5 Aufrufen wird der Speicher gleich freigegeben. Gewalt hilft wohl.
Anscheinend Regelt der GC das lieber selber. Ok ich habe 256 MB Ram deswegen juckt ihn das nicht groß weil noch viel frei ist.
So würde ich das jetzt interpretieren.
-
Der gc arbeitet sowieso nur nach internen Vorgaben. Der Aufruf von System.gc ist so wie ein kleiner Schubs "na! könntest du nicht mal ...?" auf die er dann reagieren kann oder auch nicht (wenn nicht nötig).