Speicherresourcen schonen - WeakReferences richtig einsetzen

Status
Nicht offen für weitere Antworten.

pocketom

Bekanntes Mitglied
Das Thema wurde hier glaube ich noch nicht so explizit angesprochen und anschaulich diskutiert. Dieser Thread soll dazu dienen einen einfachen Lösungsansatz zu erhalten für die Problematik, dass Listener die nicht ausgehängt werden können, unnötigerweise Referenzen halten (z.B. auf große Objekte), die eigentlich nicht mehr benötigt werden. Die Folge ist das der GarbageCollector Probleme bekommen kann diese Objekte als nicht mehr länger benötigt zu erkennen -> der Speicher läuft voll.
Dieser Beitrag resultiert aus der in diesem Thread bereits näher erläuterten Problematik: www.java-forum.org/de/topic51357_garbage-collector-funktioniert-nicht-richtig.html


hier nochmal der Beispielcode (nochmal ein klein wenig angepasst), von dem ich mir im Resultat wünschen würde dass er mit WeakReferences so "getuned" wird, dass eine resourcenschone Speichernutzung zur Laufzeit erreicht wird.

Code:
//  creates at least 64 MB of finest pure garbage
public class MyGarbage{

            private byte garbagearray[];
            
            // Construktor
            myGarbage(){            
                  garbagearray = new int[67108864];
            }
}

Code:
// the GUI class

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;


public class AppMain{   
   
   
   public static void main(String[] args) throws Exception
   {   
      MyGarbage garbage;

      Display display = new Display();
      final Shell shell = new Shell(display);
      shell.setLayout(grd);
      shell.open();
      
      // Dropdownmenu
      Menu bar = new Menu (shell, SWT.BAR);
      shell.setMenuBar (bar);
      MenuItem fileItem = new MenuItem (bar, SWT.CASCADE);
      fileItem.setText ("&File");
         // Submenu         
         Menu filesubmenu = new Menu (shell, SWT.DROP_DOWN);
         fileItem.setMenu (filesubmenu);
         
         
            
            // Menuitem Use Memory
            MenuItem usemem_item = new MenuItem (filesubmenu, SWT.PUSH);
            usemem_item.setText ("Use Memory");

            usemem_item.addListener (SWT.Selection, new Listener () {
               public void handleEvent (Event e) {
                  
                  ////////////////////////////
                  // MAKE A LOT OF GARBAGE //
                  //////////////////////////
                  garbage = new myGarbage();
               }
            });            
            
            // Menuitem Run GC
            MenuItem gc_item = new MenuItem (filesubmenu, SWT.PUSH);
            gc_item.setText ("Run GC");

            gc_item.addListener (SWT.Selection, new Listener () {
               public void handleEvent (Event e)
               {                  
                  /////////////////////////
                  // COLLECT GARBAGE !!!//
                  ///////////////////////
                  Runtime.getRuntime().runFinalization();
                  System.gc();
                  Runtime.getRuntime().gc(); 
               }
            });

      while (!shell.isDisposed ()) {
         if (!display.readAndDispatch ()) display.sleep ();
      }      
      display.dispose ();
   }
}

hier ein paar Resourcen für alle Interessierten:
java.sun.com/j2se/1.4.2/docs/api/java/lang/ref/WeakReference.html
SUN Article - Tuning Javas Garbage Collection
http://www.javaworld.com/javaworld/javatips/jw-javatip79.html?page=1
Plugging memory Leaks with weak references


---------------------------

Ich Peil im Moment leider garnicht wo ich die WeakReference am besten einsetzen soll? Mein Datenobjekt wird am Beginn von Main() instanziiert, soll ich die WeakReference bereits hier machen? Oder eher in meiner FileOpen() Funktion auf mein Objekt FileParser()? Oder soll ich als Rückgabewert der Funktion eine WeakReference zurückgeben? Habe jetzt schon mehrere Möglichkeiten durchprobiert, bis jetzt ohne Erfolg.
 
S

SlaterB

Gast
> Ich Peil im Moment leider garnicht wo ich die WeakReference am besten einsetzen soll?

das ist der falsche Ansatz, erstmal musst du doch überlegen,
warum und wofür du das überhaupt einsetzen willst

> Mein Datenobjekt wird am Beginn von Main() instanziiert, soll ich die WeakReference bereits hier machen?
> Oder eher in meiner FileOpen() Funktion auf mein Objekt FileParser()?
> Oder soll ich als Rückgabewert der Funktion eine WeakReference zurückgeben?

wenn alle drei Möglichkeiten keinen Unterschied machen,
dann ist doch egal welche..
> Habe jetzt schon mehrere Möglichkeiten durchprobiert, bis jetzt ohne Erfolg.

wie zeichnet sich ein Erfolg aus?,
was willst du überhaupt, was passiert stattdessen?

------------------

hab jetzt mal ein wenig damit rumprobiert, ganz interessante Sache,

was mir so bisher aufgefallen ist:
wird ein großer Datenblock in einer Operation in einem untergeordneten Block erzeugt,
dann macht der GC machmal nichts bis zum Ende der Operation (abhängig von sonstger Speicherbeanspruchung),

bei mehreren Blöcken werden nach einer gewissen Speicherbelastung einige entfernt

sind die Blöcke eine for-Schleife, dann räumt GC komplett auf..

am besten wird das Objekt in einer anderen Operation erzeugt, dann klappt GC am Ende auch bei nur einem Aufruf

----

bei WeakReferences passieren im Großen und Ganzen nachvollziehbare Dinge,
ein bisschen Speicher wird belegt, teilweise sofort freigegeben,

auf jeden Fall beim gc-Aufruf (oder einfach nur Thread.sleep()?),
sofern das enthaltene Objekt nicht auf andere Weise behalten wird (z.B. lokale Variable in Unterblock)




wenn du genauer erzählen würdest, worum es geht, dann könnte man es gezielter verfolgen,
und dein SWT kannst du in die Tonne treten, dann kannst du gleich gar kein Code posten..,
Swing ist das einzig wahre ;)

Code:
public class TestKonsole {
	static List list = new ArrayList();
	static long time = System.currentTimeMillis();

	public static void main(String agrs[]) throws Exception {
		ps("Anf  ");
		
		
		
		{
			int[] a = new int[100000];
			list.add(new WeakReference(a));
		}
		
		
		
		//{
		//	list.add(new WeakReference(new int[100000]));
		//}



		//for (int i = 0; i < 9; i++) {
		test();
		//test2();
		//}
		
		
		
		ps("nach ");
		//System.gc();
		//System.gc();
		Thread.sleep(1000);
		ps("Ende ");
	}

	public static void test() {
		list.add(new WeakReference(new int[30000]));
		ps("test ");
	}
	public static void test2() {
		list.add(new WeakReference(new int[70000]));
		ps("test2");
	}

	public static void ps(String info) {
		Runtime runtime = Runtime.getRuntime();
		String memory = runtime.maxMemory() + ", ";
		memory += runtime.totalMemory() + ", ";
		memory += runtime.freeMemory();

		long actTime = System.currentTimeMillis() - time;

		p(info + " " + memory + " - " + toStringListWR(list) + ", " + actTime);
	}

	public static String toStringListWR(List list) {
		String st = "";
		for (int i = 0; i < list.size(); i++) {
			st += ((WeakReference) list.get(i)).get() + ", ";
		}
		return st;
	}

	public static void p(Object o) {
		System.out.println(o);
	}
}
 

pocketom

Bekanntes Mitglied
das ist der falsche Ansatz, erstmal musst du doch überlegen,
warum und wofür du das überhaupt einsetzen willst

wie zeichnet sich ein Erfolg aus?,
was willst du überhaupt, was passiert stattdessen?

Ich quote mich einfach mal selber :wink:

Dieser Beitrag resultiert aus der in diesem Thread bereits näher erläuterten Problematik: www.java-forum.org/de/topic51357_garbage-collector-funktioniert-nicht-richtig.html
( Da steht alles ausführlich drin. Will fette Objekte einfach gezielt aufräumen)




wenn du genauer erzählen würdest, worum es geht, dann könnte man es gezielter verfolgen,
und dein SWT kannst du in die Tonne treten, dann kannst du gleich gar kein Code posten..,
Swing ist das einzig wahre

Das SWT fürn A**** ist weiss ich mittlerweile auch, aber das Projekt existiert jetzt nunmal so. Versuchs einfach mal analog durch die SWING-Brille zusehen :wink:
Auf SWING steige ich in der nächsten Version um, genau wie von GNU 1.4.2 auf SUN 6u1,... Im Moment interessierts mich nur prinzipiell wie es geht. Der Code sagt doch im Prinzip alles, oder kannst ihn wegen SWT-Allergie nicht lesen? Ich möchte einfach nur den Müll von dem ich weiss das ich ihn nicht mehr brauche gezielt loswerden, der Code dient nur zur Veranschaulichung. Betrachte es als Pseudocode oder so....
 
S

SlaterB

Gast
der Link zum anderen Thread ist mir durchaus aufgefallen,
ich bezog meine Kritik natürlich auf beide,

was du von 500 MB-Objekten zusammenreimst tut nicht zur Sache,
das kann ich ja eh nicht nachtesten/ hat auch mit deinem Code nix zu tun,

in deinen Code taucht nirgendo WeakReference auf und auch sonst nix, wofür du das brachst oder so,
einfach null, null komma nix,

in deinen Listener erzeugst du irgendwo lokale Daten, die nirgendwo verwendet werden
1)
um das zu testen müsstest du daraus normalen Swing-Code machen,
ansonsten ist das nicht zu gebrauchen,

ich unterstelle gerne böse, dass SWT insgeheim alle Objekte auf ewig cacht ;)

2)
was hat das mit WeakReferences zu tun?
 
S

SlaterB

Gast
hmm, also ok,
wenn nur ein kleiner Teil des Speichers belegt wird, wird dieser ohne eigenen GC-Aufruf nicht unbedingt wieder freigegeben,
egal ob als WeakReference oder nicht oder in einem Listener oder sonst wo erzeugt,
egal wieviel Zeit man den GC lässt,

ist ja auch erstmal nicht schlimm,
bei mir reagiert der GC übrigends auf einen Aufruf..
wird das bei dir vielleicht einfach nicht ausgefuhrt? bau doch ne Systen.out.println-Meldung mit ein

Code:
public class GUI extends JFrame {

	static List list = new ArrayList();
	static long time = System.currentTimeMillis();

	public GUI() {

		JButton bMem = new JButton("Mem");
		bMem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
					ps("     Mem  ");

			}
		});

		JButton bGar = new JButton("Garbage");
		bGar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				ps("vor  Garb ");
				new MyGarbage();
				ps("nach Garb ");
			}
		});

		JButton bGC = new JButton("GC");
		bGC.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				ps("vor  GC   ");
				Runtime.getRuntime().runFinalization();
				//	System.gc();
				System.gc();
				//	Runtime.getRuntime().gc();
				Runtime.getRuntime().gc();
				ps("nach GC   ");
			}
		});

		JPanel p = new JPanel();
		p.add(bMem);
		p.add(bGar);
		p.add(bGC);
		getContentPane().add(p);
		setSize(400, 400);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}

	public static void main(String[] args) {
		new GUI();
	}

	public static void ps(String info) {
		Runtime runtime = Runtime.getRuntime();
		String memory = runtime.maxMemory() + ", ";
		memory += runtime.totalMemory() + ", ";
		memory += runtime.freeMemory();

		long actTime = System.currentTimeMillis() - time;

		p(info + " " + memory + " - " + toStringListWR(list) + ", " + actTime);
	}

	public static String toStringListWR(List list) {
		String st = "";
		for (int i = 0; i < list.size(); i++) {
			st += ((WeakReference) list.get(i)).get() + ", ";
		}
		return st;
	}

	public static void p(Object o) {
		System.out.println(o);
	}
}

interessant finde ich noch, dass bei jedem Aufruf eines Buttons 5-10 KB Speicher belegt werden..
 
S

SlaterB

Gast
wenn ich meine bescheidenen 66 MB Standardspeicher mit einem 10 Mio.-int-Array ausnutze,
wird sogar der Gesamtspeicher vom GC wieder freigegeben und im Windows-Taksmanager sinkt die Speicherbelastung wieder,

aber erst beim zweiten GC-Aufruf

Code:
//           max-Mem   total   free        Milli-Zeit seit Programmstart


     Mem   66650112, 2031616, 1502208 - , 2223
     Mem   66650112, 2031616, 1494472 - , 3815
vor  GC    66650112, 2031616, 1458256 - , 5428
nach GC    66650112, 2031616, 1726680 - , 5638
     Mem   66650112, 2031616, 1697080 - , 7280
vor  Garb  66650112, 2031616, 1659512 - , 9694
nach Garb  66650112, 42070016, 1729104 - , 10014
     Mem   66650112, 42070016, 1701456 - , 12188
     Mem   66650112, 42070016, 1694040 - , 14180
vor  GC    66650112, 42070016, 1664352 - , 15813
nach GC    66650112, 40361984, 40078896 - , 16053
     Mem   66650112, 40361984, 40039784 - , 21932
vor  GC    66650112, 40361984, 40004664 - , 26258
nach GC    66650112, 2031616, 1747880 - , 26478
     Mem   66650112, 2031616, 1693352 - , 28922
 

pocketom

Bekanntes Mitglied
Scheint unter Swing auf jeden Fall besser zu funktionieren. Habe das gleiche mit SWT nochmal gebaut, da wird der Speicher erstmal so richtig schön vollgeschaufelt.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben