ImageIO.read verursacht heap space

Status
Nicht offen für weitere Antworten.

ulr!ch

Bekanntes Mitglied
Hi JavaGemeinde,

ich habe nun die letzten drei Tage damit zugebracht, alle möglichen Foren, APIs, Codebsp. ... nach einer Lösung durchzuforsten, deswegen schickt mich bitte nicht weg. :(
Also, folgendes Problem, ich habe einen JTabbedPane, auf dem bis zu 25 Panels als KarteiKarten angezeigt werden. Auf den Panels sind JLabel, die über new ImageIcon() ein BufferedImage darstellen. Dieses BufferedImage besteht aus einer png-Datei (ca. 750 x 350 px), auf die zusätzlich noch ein paar Striche gezeichnet werden müssen.
Wenn ich nun das erste Mal die 25 Panels mit den 25 Labels anzeigen lasse, funktioniert alles einwandfrei, auch beim zweiten Mal, aber beim Dritten mal sind die 64MB heap space aufgebraucht, und dass obwohl ich
a) das JTabbedPane lösche,
b) das Panel lösche,
c) flush() und System.gc() ein paar Mal drin stehen habe...

Ich hab' echt alles ausprobiert. Hier mal ein wenig Code:
Code:
importe [...]

public class profil extends JFrame {
  private static BufferedImage bimage = new BufferedImage(750, 350, BufferedImage.TYPE_INT_RGB);

  public BufferedImage getBufferedImage([...]) {
    try {
// Bimage mit ImageIO aus einer png-Datei laden
        try {
        	bimage = ImageIO.read(new File("X:/[...]/abc.png"));  // wird das 52 Mal aufgerufen, hängt's
        }
        catch (IOException e) {
           e.printStackTrace();
        } 
    }
    catch (NullPointerException npe) {
      System.out.println(npe);
    }

// Linien zeichnen
    Graphics g = bimage.getGraphics();
    Graphics2D linie = (Graphics2D) g;
//    [blabla]
    
    repaint();
    return(bimage);
  }
}

Kann jemand helfen?

Liebe Grüße,
Ulr!ch
 

ulr!ch

Bekanntes Mitglied
Wildcard hat gesagt.:
Wenn du 3 Bilder hast solltest du 3 Bilder laden und nicht 25.
Hi Wildcard,

ich verstehe immer noch nicht, wie das mein Problem löst. :?
Wenn ich Bild A habe, dass dann die Grundlage für die Bilder 1, 14, 15, 16 und 20 ist, dann muss ich Bild A ja irgendwie vervielfältigen. Und dann habe ich dann hinter doch wieder 6 Referenzen (eine auf Bild A, Bild A(1) usw.).

Es geht doch um die Anzahl der Referenzen.
Kannst du vielleicht ein wenig genauer beschreiben, was du meinst?

Danke im Voraus,
Ulr!ch
 

Wildcard

Top Contributor
Warum vervielfältigen? Du kannst das gleiche Bild immer wieder verwenden.
Schreib dir eine ImageRegistry dafür, die die Bilder in einen internen Cache lädt:
Code:
public class ImageRegistry {
	private static HashMap<String, BufferedImage> registy = new HashMap<String, BufferedImage>();
	
	public static BufferedImage getImage(String path)
	{
		BufferedImage image = registy.get(path);
		if(image!=null)
			return image;
		return loadImage(path);
	}

	private static BufferedImage loadImage(String path) {
		try {
			return ImageIO.read(new File(path));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}
 

ulr!ch

Bekanntes Mitglied
Hi Wildcard,

danke für deine Antwort. Ich befürchte, ich bin zu blöd... :(
Ich muss doch irgendwie die HashMap füllen und das mache ich doch mit registy.put("abc", bufferedImage);

Und später rufe ich dann doch die externe Klasse mit:
Code:
Graphics g = ImageRegistry.getImage("X:/[...]/1.png").getGraphics();
    Graphics2D linie = (Graphics2D) g;
auf, oder?

Sorry, dass ich jetzt auf den Keks gehe, aber meine Nerven sind echt am Ende...
Wie kann ich also die HashMap füllen?

Liebe Grüße,
Ulr!ch
 

Wildcard

Top Contributor
Ach ja, das put hatte ich vergessen, das solltest du in load einbauen, sonst bringt das ganze nicht viel :lol:
 

ulr!ch

Bekanntes Mitglied
Wildcard hat gesagt.:
Ach ja, das put hatte ich vergessen, das solltest du in load einbauen, sonst bringt das ganze nicht viel :lol:
Hi Wildcard,

dann sieht die Klasse nun so aus:
Code:
   public class ImageRegistry {
	   private static HashMap<String, BufferedImage> registy = new HashMap<String, BufferedImage>();
	   private static BufferedImage bi01 = new BufferedImage(750, 350, BufferedImage.TYPE_INT_RGB);

	   public static BufferedImage getImage(String path)
	   {
	      BufferedImage image = registy.get(path);
	      if(image!=null)
	         return image;
	      return loadImage(path);
	   }

	   private static BufferedImage loadImage(String path) {
	      try {
	   	   registy.put(path, bi01);
	    	  return ImageIO.read(new File(path));
	      } catch (IOException e) {
	         // TODO Auto-generated catch block
	         e.printStackTrace();
	      }
	      return null;
	   }
	}

Und um auf dieses BufferedImage zeichnen zu können, rufe ich folgendes auf:
Code:
   bimage =ImageRegistry.getImage("X:/[...]/abc.png");
    Graphics g = bimage.getGraphics();
    Graphics2D linie = (Graphics2D) g;

Wenn ich die Klasse, in der der zweite Codeabschnitt steht, mehrmals aufrufe, dann schreibt er mir:
a) ab der zweiten Karteikarte alle Striche übereinander,
b) lädt er das Bild nicht mehr und
c) verstehe ich nicht zum zeichnen rufe ich ImageRegsitry.getImage(String path) auf, die dann wiederum loadImage(String path) aufruft. Hier wied jedesmal ImageIO.read(new File(path)) aufgerufen. Wo liegt hier die Vereinfachung. :)

Sorry, ich versteh's nicht. Vielleicht kannst du das noch mal drüberschauen; wo liegt mein logischer Fehler?

Alles Gute,
Ulr!ch
 

Wildcard

Top Contributor
Ist denn jedes Bild anders bemalt? Das hast du vorher zB nicht erwähnt.
Wenn es der Fall ist, zeichne lieber in der Component die das Bild enthält die Striche oben drauf, als zig Bilder in den Speicher zu klopfen und dich dann zu wundern wenn er irgendwann ausgeht.
 

ulr!ch

Bekanntes Mitglied
Wildcard hat gesagt.:
Ist denn jedes Bild anders bemalt? Das hast du vorher zB nicht erwähnt.
Wenn es der Fall ist, zeichne lieber in der Component die das Bild enthält die Striche oben drauf, als zig Bilder in den Speicher zu klopfen und dich dann zu wundern wenn er irgendwann ausgeht.
Ja, jedes Bild ist anders bemalt. Gott sei Dank, ich dachte schon, ich hätte was grundlegendes verpeilt. :)

Die Komponente, auf die dann gezeichnet würde, wäre ein JLabel. Wenn ich dich richtig verstehe, dann setIcon(new ImageIcon())? Dann kann ich mit Graphics g darauf zeichnen, ohne dass ich das Bild darunter "lösche"?

Wenn du mir da noch ein wenig Info geben kannst.

Liebe Grüße,
Ulr!ch
 

Wildcard

Top Contributor
Überschreib paintComponent, ruf als erstes super.paintComponent auf und danach kannst du Linien zeichnen.
 

ulr!ch

Bekanntes Mitglied
Ok, Wildcard, das war ein echt großer Schritt in die richtige Richtung. :applaus:
Jetzt habe ich nur noch ein kleines Problem, und zwar folgendes:

Code:
 public class profil extends JLabel {
  int gesamt;
  Double[] zahlenX;
  
  public profil(int gesamt, Double[] zahlenX) {
	  this.gesamt = gesamt;
	  this.zahlenX = zahlenX;

// 1. Aufruf
	  System.out.println("--> "+gesamt);
	  System.out.println("--> "+zahlenX[1]+"; "+zahlenX[2]);

          setIcon(new ImageIcon("X:/[...]/abc.png"));
          repaint();
  }

  public void paintComponent(Graphics g) {
// 2. Aufruf
  	System.out.println("-->2 "+gesamtScore);
  	System.out.println("-->2 "+zahlenX[1]+"; "+zahlenX[2]);

  	super.paintComponent(g);
// Linie - int
	  Graphics2D linie = (Graphics2D) g;
    	  linie.drawLine((int)(250+50*(new Double(gesamt))), 50,
	    		       (int)(250+50*(new Double(gesamt))), 50);
// Linie - Double[]
  	  linie.drawLine(new Double(xKoordinaten[i]+50*zahlenX[i].doubleValue()).intValue(), yKoordinaten[i],
	  		       	   new Double(xKoordinaten[i+1]+50*zahlenX[i+1].doubleValue()).intValue(), 
  }
}

Und bei der ersten Consolenausgabe werden int und Double[] richtig angezeigt, beim zweiten Aufruf werden int und Double[] vom letzten Aufruf angezeigt. Nun kommt aber das verrückte. Die Linie - int wird korrekt gezeichnet, also variable, wohingegen die Linie - Double[] immer dieselbe ist, obwohl die übergebenen Werte unterschiedlich sind.
Ich versteh' die Welt nicht mehr...
:shock: Wie kann denn das sein? ???:L
Hast du vielleicht darauf eine Antwort bzw. einen Ansatz zum Lösen.

Liebe Grüße,
Ulr!ch
 

ulr!ch

Bekanntes Mitglied
Hi,

ich bin's noch einmal. Das spuckt die Konsole aus.
Ich verstehe nicht - und vielleicht liegt da das Problem - weshalb der repaint-Befehl also der Aufruf von paintComponent so spät erfolgt...

Code:
--> 35
--> 300; 508
--> 33
--> 440; 422
--> 24
--> 343; 344
-->2 35
-->2 343; 344
-->2 35
-->2 343; 344

Seltsam...
Liebe Grüße,
Ulr!ch
 

trazzag

Bekanntes Mitglied
wo kommen denn die Arrays xKoordinaten und yKoordinaten her? Und wo / wie dein i definiert ist, sehe ich auch irgendwie noch nicht.
 

ulr!ch

Bekanntes Mitglied
trazzag hat gesagt.:
wo kommen denn die Arrays xKoordinaten und yKoordinaten her? Und wo / wie dein i definiert ist, sehe ich auch irgendwie noch nicht.
Die Arrays kommen von der aufrufenden Klassen, das zumindest könnte man sehen.
Das i ist ein Laufparameter einer for-Schleife, die ich rausgenommen habe, um den code übersichtlicher zu machen.

Das Problem ist, die Arrays werden zwar korrekt übergeben, zu dem Zeitpunkt, an dem die paintComponent jedoch aufgerufen wird, hat der letzte Eintrag alles andere überschrieben. Ich fände es logisch, wenn es bei dem int genauso wäre, ist es aber nicht...

Liebe Grüße,
Ulr!ch
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
M "ImageIO.read()" liest Bild nicht richtig ein AWT, Swing, JavaFX & SWT 3
B Probleme bei ImageIO.read (?!) AWT, Swing, JavaFX & SWT 9
B ImageIO.read() zweimal hintereinander aus ObjectInputStream funktioniert nicht AWT, Swing, JavaFX & SWT 4
M Bild Beschreibung mit ImageIO speichern AWT, Swing, JavaFX & SWT 1
B Problem mit ImageIO.write() AWT, Swing, JavaFX & SWT 7
B ImageIO und animerte gifs? AWT, Swing, JavaFX & SWT 4
N ImageIO Endung mitgeben AWT, Swing, JavaFX & SWT 4
M ImageIO, Bilderordner durchblättern AWT, Swing, JavaFX & SWT 4
B ImageIO gif Dateien laden AWT, Swing, JavaFX & SWT 7
S toolkit vs. imageIO AWT, Swing, JavaFX & SWT 4
T Swing ImageIO - nicht abfangbare IOException AWT, Swing, JavaFX & SWT 5
B Problem mit imageIO und ImageIcon AWT, Swing, JavaFX & SWT 5
G Problem mit BufferedImage und imageIO AWT, Swing, JavaFX & SWT 2
H ImageIO.write-Probleme, Speicherüberlauf und Absturz AWT, Swing, JavaFX & SWT 12
I BMP mit ImageIO schreiben AWT, Swing, JavaFX & SWT 1
Umb3rus JavaFX Problem mit PropertyValueFactory: can not read from unreadable property AWT, Swing, JavaFX & SWT 1
G textarea.read funzt net in Jar-Datei AWT, Swing, JavaFX & SWT 7
S ChangedCharSetException bei HTMLEditorKit.read() AWT, Swing, JavaFX & SWT 2
J JTable verursacht NullPointerException.Ratlos. AWT, Swing, JavaFX & SWT 5
N Countdown verursacht Speicher Leak AWT, Swing, JavaFX & SWT 7
J JList verursacht Absturz AWT, Swing, JavaFX & SWT 29
B JTable ValueChanged verursacht Exception AWT, Swing, JavaFX & SWT 3
M JTable verursacht NullPointerException AWT, Swing, JavaFX & SWT 8

Ähnliche Java Themen


Oben