Erste Schritte Speicher läuft voll, Diashow, Images

TryAndError

Mitglied
Problem: Ich versuche eine Diashow zu schreiben. doch wenn ich sie laufen lasse Zählt der Speicher hoch bis ein Java heap space Fehler kommt. Ich müsste also wissen wie ich die Images so lade, dass sie sich stehts überschreiben oder wie ich die nicht mehr benötigten Images lösche.

Java:
...
        public void run() 
	{
		MediaTracker LadeKontrolle = new MediaTracker(this);//Ladeüberwachung Inizialisiren
		Toolkit tk = getToolkit();
		for (int i=544; i<ShowL;++i){
		   Bilder=null;	
		   Bilder=tk.getImage(Liste[i]);				//Bild Laden
		   LadeKontrolle.addImage(Bilder, 0);			//Ladeüberwachung auf Bild
		   try {												//
			   System.out.println("Laden Bild "+i);			//für mich zum Triggern
			   LadeKontrolle.waitForAll();					//Warten bis Laden beendet
			   System.out.println("Ende Bild");				//für mich zum Triggern
		   } catch (InterruptedException e){
		       break;
		   }
		   repaint();
		   try {
			   Thread.sleep(Zeit);
		   } catch (InterruptedException e){
		       //break;
		   }
		}
	}

        public void paint(Graphics g)
	{
	   
	    if (Bilder != null)	
	    {
		ScaldB = Bilder.getScaledInstance(WinLa, WinHi, 1); 
	    	MediaTracker LadeKontrolle = new MediaTracker(this);
		LadeKontrolle.addImage(ScaldB, 0);
		try {
			LadeKontrolle.waitForAll();
				
		     } catch (InterruptedException e){
				
		     }
			
		g.drawImage(ScaldB, 0, 0, this);
		
		    
	    }	
	}
...
 
Zuletzt bearbeitet:
1. wie hoch ist die Sleeptime (Zeit) in der "run()"-Methode?
2. Den MediaTracker würde ich ohnehin irgendwie statisch (i mean not static 😉) machen, so dass er nicht immer neu instanziert werden muss.
3. Auf keinen Fall würde ich die Bilder, die schon geladen wurden, immer wieder neu laden.

Alles in allem glaube ich, das einzige, was dieses Programm tut, ist den GarbageCollector belasten, der mit seinen Aufräumarbeiten gar nicht hinterher kommt. 100% Prozessorauslastung und am Ende der besagte Out of Memory (Heapspace) sind hier kaum verwunderlich.
 
Vielen dank für die Promte Antwort. Ich habe das mit dem Mediatrecker gleich mal umgesetzt und hab dabei noch ein paar andere Probleme gelöst. Daher erst die späte Antwort.
Die Sleepzeit ist was immer man will, 1000...6000... ^ 1sec...6sec..., jeh nach dem wie lange ich das Bild anzeigen will.
Wird das Bild1 angezeigt, das Bild2 geladen und angezeigt, dann ist das Bild1 für mich unwichtig, die Daten können gelöscht, ungelodet oder was auch immer werden (Diashow eben).
Somit, ja das Programm belastet den GarbageCollector wie kann ich das verhindern.
Java:
public void run() 
	{
		
		int X, Y;
		MediaTracker LadeKontrolle = new MediaTracker(this); //Ladeüberwachung Inizialisiren
		Toolkit tk = getToolkit();
		
		for (int i=544; i<ShowL;++i){
		   	
		   Bilder=tk.getImage(Liste[i]);				        //Bild Laden
		   LadeKontrolle.addImage(Bilder, 0);					//Ladeüberwachung auf Bild
		   
		   try {												//
			   System.out.println("Laden Bild "+i);				//für mich zum Triggern
			   LadeKontrolle.waitForAll();						//Warten bis Laden beendet
			   System.out.println("Ende Bild");				//für mich zum Triggern
		   } catch (InterruptedException e){
		       break;
		}
		   //**************************************
		   		   
		Y=Bilder.getHeight(null);
	    	X=Bilder.getWidth(null);
	    	//Der Frame wird hochkant oder quer gestellt je nach Bildformat (ist nur ein experiment)
                if (X>Y){					                              //			 ||
	    		setSize(800, 600);			                      //			 ||
	    		WinLa=800;				                              //			 ||
	    		WinHi=600;				                              //			 ||
	    		setLocation(WinPoX,WinPoY);		                      //			 ||
	    	}else{						                      //			 ||
	    		setSize(600, 800);			                      //			 ||
	    		WinLa=600;				                              //			 ||
	    		WinHi=800;				                              //			 ||
	    		setLocation(WinPoX+100,WinPoY-100);	              //			 ||
	    	}						                              //			 ||
		
	    	// Diesen Block habe ich von *Paint* hochkopiert damit ich den MediaTracker mitbenutzen kann

	    	ScaldB = Bilder.getScaledInstance(WinLa, WinHi, 0); 
	    		LadeKontrolle.addImage(ScaldB, 0);
			try {
				//System.out.println("Laden Scald");
				LadeKontrolle.waitForAll();
				//System.out.println("Ende Scald");
			} catch (InterruptedException e){
				
			}
			
	    	
		   Bilder=ScaldB;
		  
		   repaint();
		   
		   try {
			   Thread.sleep(Zeit);
		   } catch (InterruptedException e){
		       
		   }
		}
	}


public void paint(Graphics g)
	{
	    
		if (Bilder != null)	
	    {
			
		    g.drawImage(Bilder, 0, 0, this);
		    
	    }	
	}
 
Zuletzt bearbeitet:
Also der Garbage-Collector wird bei 1s Timeout eigentlich gar nicht mehr belastet, der Effekt stellt sich mehr oder weniger erst im 1/100s-Bereich und darunter ein, deswegen stellte ich ja auch die Frage, wie lange "time" eigentlich dauert.
Der Mediatracker wird bei dir in der "run()"-Methode pro Durchlauf immer wieder neu instanziert, das ist nicht notwendig oder mit anderen Worten überflüssig. Es genügt, wenn man ihn einmal bei der Instazierung der Component (Canvas, Panel, Applet usw. inkl. Swing) als "private" oder "public final" Attribut mit instaniert, für Toolkit gilt selbiges.
Java:
public class MyPanel
extends Panel
{
  public final MediaTracker ladeKontrolle;
  private ToolKit toolKit;

  public MyPanel()
  {
    ladeKontrolle = new MediaTracker(this);
    toolKit = getToolkit();
  }

  public void run()
  {
    Image tmp = null;
    for (int i=544; i<ShowL;++i){
      Bilder=null; 
      tmp=tk.getImage(Liste[i]);                //Bild Laden
      ladeKontrolle.addImage(tmp, 0);           //Ladeüberwachung auf Bild
      try {                                                //
        System.out.println("Laden Bild "+i);         //für mich zum Triggern
        ladeKontrolle.waitForAll();                  //Warten bis Laden beendet
        System.out.println("Ende Bild");             //für mich zum Triggern

        // ... Scale-Code (mit tmp & nicht Bilder !!!)

        Bilder = tmp; // die in paint() verwendete Variabel enhält jetzt definitiv ein geladenes Bild
        repaint();
        Thread.sleep(Zeit);
      } catch (InterruptedException e){
        interrupt(); // <--------------DAS sollte man in Threads bzw. Runnables nicht vergessen.
        return; //                            und gleich raus aus run();
      }
    }
  }

  public void paint(Graphics g)
  {
    try {
      while(Bilder == null) {
        Thread.sleep(10);
      }
      g.drawImage(Bilder, 0, 0, this);
    } catch(InterruptedException ie) {
        // nothing
    }
  }
}
 
O.K. Ich habe den MT und TK umgebaut, hat sogar funktioniert. (Ich meine bei mir hats funktioniert)
Für die Pausen habe ich jetzt sogar ein extra eingebaut 1/200 pauschal nochmal zu der die in der jetztigen Version berechnet wird und somit auch unter 1/100 sein kann.
Ich habe sogar die Metode "System.gc()" gleich mehrfach eingebaut und vorweg die Imag-Variablen auf "*=null;" gesetzt. Leider läuft der Speicher immer noch voll.
Das Programm sieht jetzt so aus:
Java:
public void run() 
	{
		int X, Y, Xneu=WinLa, Yneu=WinHi, Xmov, Ymov, Step, h, MovZeit;
		Boolean Quer=true;
		Image tmp=null;
		for (int i=Start; i<ShowL;++i){
		   Bilder=null;	// "Bilder" müsste jetzt leer sein
		   System.gc();   // Garbage-Collector Zeit
		   tmp= tk.getImage(Liste[i]);				//Bild Laden
		   LadeKontrolle.addImage(tmp, 0);			//Ladeüberwachung auf Bild
		   try {							// nur noch ein Try für alles
		       
		       LadeKontrolle.waitForAll();					//Warten bis Laden beendet

 // ... Scale-Code (mit tmp & nicht Bilder !!!)
    
                       repaint();
		       Thread.sleep(Zeit); // Zeit > 3000
		       Thread.sleep(200); // Zursicherheit sollte Zeit mal <100 sein
		
		   } catch (InterruptedException e){
			   //interrupt();
			   return; 
			   //break;
		   }//try
		}    //for i 
	}//run
	
	
	public void paint(Graphics g)
	{
	    
	    
	    if (Bilder != null)	
	    {
		g.drawImage(Bilder, 0, 0, this);
		System.gc(); 
		    
	    }	
	}
 
Zuletzt bearbeitet:
Also bei mir läuft's ohne dem ständigen Aufruf von "System.gc()" mit 13 JPegs mit 1024 * 768 Punkten und das sogar im Widerholmodus (mehr dazu später) über mehrere Stunden. Das zusätzliche Thread.sleep(200) kannst dir sparen, "Thread.sleep(Zeit + 200)" wäre hier viel eleganter, ist aber dennoch überflüssig, weil per "mt.waitForAll()" ohnehin auf Beendigung des Ladevorganges gewartet wird.
Was man noch machen könnte, wäre in der "paint()"-Methode ein Bild anzeigen zu lassen, während ein weiteres in der "run()"-Methode geladen wird. Zum Widerholmodus und dem zuletzt erwähnten mal ein KSKB.
Java:
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public final class Diashow
extends Frame
implements Runnable
{
	private static final long serialVersionUID = 1L;
	private final MediaTracker mt;
	private final Toolkit tk;
	private final long time = 3000L;
	private Thread runner;
	private Image Bilder;
	private String[] Liste;

	private Diashow()
	{
		mt = new MediaTracker(this);
		tk = getToolkit();
		List<String> path = createList(new File("/absoluter/pfad/zum/bildverzeichnis"), null);
		Liste = path.toArray(new String[path.size()]);
	}

	private List<String> createList(File f, List<String> rc)
	{
		if(rc == null) {
			rc = new ArrayList<String>();
		}
		f = f.getAbsoluteFile();
		if(f.isDirectory()) {
			File[] list = f.listFiles();
			for(int n = 0; n < list.length; n++) {
				createList(list[n], rc);
			}
		} else {
			rc.add(f.getAbsolutePath());
		}
		return rc;
	}

	public static void main(String[] args)
	{
		Frame f = new Diashow();
		f.setSize(1024, 768); // grösse vllt. anpassen
		f.setUndecorated(true);
		f.setVisible(true);
	}

	@Override
	public void run()
	{
	    Image tmp = null;
	    int i = 0;
	    while(!runner.isInterrupted()) {
	      Bilder=null; 
	      tmp=tk.getImage(Liste[i]);                //Bild Laden
	      mt.addImage(tmp, 0);           //Ladeüberwachung auf Bild
	      try {                                                //
	        System.out.println("Laden Bild "+(i+1));         //für mich zum Triggern
	        mt.waitForAll();                  //Warten bis Laden beendet
	        System.out.println("Ende Bild "+(i+1));             //für mich zum Triggern
	 
	        // ... Scale-Code (mit tmp & nicht Bilder !!!
	        Bilder = tmp; // die in paint() verwendete Variabel enhält jetzt definitiv ein geladenes Bild
	        repaint();
	        synchronized(runner) {
	        	runner.wait(); // hier legst du runner schlafen...
	        }
	      } catch (InterruptedException e){
	        runner.interrupt(); // <--------------DAS sollte man in Threads bzw. Runnables nicht vergessen.
	        return; //                            und gleich raus aus run();
	      }
	      i++;
	      i %= Liste.length;
	    }
	}

	@Override
	public void paint(Graphics g)
	{
		if(runner == null) {
			runner = new Thread(this);
			runner.start();
		}
		if(Bilder != null) {
			g.drawImage(Bilder, 0, 0, this);
			synchronized(runner) {
				runner.notify(); // ...hier weckst du runner wieder auf
			}
			try {
				Thread.sleep(time);
			} catch(InterruptedException e) {
				runner.interrupt();
			}
		}
	}
}
Auch dieses Beispiel läuft bei mir stundenlang, ohne dass sich im Taskmonitor auch nur eine Perfonmance-Nadel (z.B. die von der Speicherauslastung) bewegt. Wenn es bei dir gar nicht oder nur kurz läuft (z.B. wenn es nicht mal einen Durchgang der Bildreihe schafft) reicht deine Hardware (Speicher) möglicherweise nicht aus, um der JVM genug Speicher zuzuweisen. Dann müsstest du beim Start der JVM (java.exe) mal ein wenig mit den Parametern "Xms" und "Xmx" experimentieren.
 
Krank, Ulaub, Kinder- Tut mir leid das ich nicht sofort Antworten konnte.

Ich habe ein Projeckt "Diashow" ezeugt und den Code 1:1 übertragen.
Ich habe das Programm Extrahiert und als Diaschow.jar sogar auf einem anderen Rechner laufen lassen.

Ich scheine irgend etwas um 272....MByte für den Garbage-Collector zu haben. Zumindesten leuft im Taskmanager/Prozesse... ein javaw.exe Prozess und dessen Speicherauslastung erreicht irgend wann 272MB und dann werden sogar kleine Bilder nicht mehr angezeigt.

Ich hätte noch die Möglichkeit das mein Programm mit dem ich alle herstell mir dies als SharewareBuck reinhaut um mich zum kauf einer Vollversion zu bringen oder so ähnlich:

"Eclipse IDE for Java Developers
"
"Version: Helios Service Release 2
"Build id: 20110301-1815
"(c) Copyright Eclipse contributors and others 2000, 2011. All rights reserved.
"Visit Eclipse - The Eclipse Foundation open source community website.
"
"This product includes software developed by the
"Apache Software Foundation http://apache.org/"
"
 
Zuletzt bearbeitet:
Krank, Ulaub, Kinder- Tut mir leid das ich nicht sofort Antworten konnte.
Macht nix, ich muss ja nicht voran kommen 🙂
Ich hätte noch die Möglichkeit das mein Programm mit dem ich alle herstell mir dies als SharewareBuck reinhaut um mich zum kauf einer Vollversion zu bringen oder so ähnlich...
Du redest hier von Eclipse Helios? Nö, das kann der Grund nicht sein. Eclipse ist Freeware, ich verwende es auch. Im Taskmanager stellt sich bei meinen Bildformaten (1024 * 768) bei ca. 15 Bildern dort nach ca. 2 Minuten Laufzeit ein Wert von ca. 160MB ein, der Speicherverbrauch scheint also normal. Ich werde mal ausprobieren, was passiert, wenn ich per Xms und Xmx Werte unterhalb dieses Limits einstelle. Ich denke mal, das ich dadurch das selbe Problem wie du bekomme.
 

Neue Themen


Zurück
Oben