Threads ThreadPoolExecutor eigenartiges verhalten

sMau90

Aktives Mitglied
Hey,
Ich versuche um ganz viele kleine unabhängige Aufgaben parallel zu erledigen einen ThreadPool zu verwenden und benutze dafür einen ThreadPoolExecutor mit fester Größe (4).
Nun kann ich ab einem entsprechend hohen Workload folgende Meldungen beobachten:
Java:
Exception in thread "pool-1-thread-5" java.lang.OutOfMemoryError: Java heap space
	at java.awt.image.DataBufferInt.<init>(DataBufferInt.java:75)
	at java.awt.image.Raster.createPackedRaster(Raster.java:470)
	at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1032)
	at java.awt.GraphicsConfiguration.createCompatibleImage(GraphicsConfiguration.java:149)
	at java.awt.GraphicsConfiguration.createCompatibleImage(GraphicsConfiguration.java:178)
	at org.jdesktop.swingx.util.GraphicsUtilities.toCompatibleImage(GraphicsUtilities.java:321)
	at org.jdesktop.swingx.util.GraphicsUtilities.loadCompatibleImage(GraphicsUtilities.java:270)
	at de.netprojectev.Media.ImageFile.loadImageFileFromDisk(ImageFile.java:106)
	at de.netprojectev.Media.ImageFile.generateDisplayImage(ImageFile.java:131)
	at de.netprojectev.Media.ImageGenerationTask.run(ImageFile.java:45)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:722)
Danach sehe ich noch mehr solcher Exceptions, bis dann irgendwann (nach ein paar Sekunden) wieder ein paar Aufgaben erledigt werden, wobei zwischendurch immer sowas im Log auftaucht:
Java:
Exception in thread "pool-1-thread-10" java.lang.OutOfMemoryError: Java heap space
So erstelle ich den ThreadPool
Java:
	public static ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(4);

Ich verstehe zwei Sachen nicht. Erstens warum z.B. "Thread-10" in der Meldung auftaucht, es sollten doch eigentlich nur 4 sein. Und wie kommt das OutOfMemory Problem zu Stande?

Falls es auch interessant ist was in den Worker Thread gemacht wird:
Ich lade Bilder von der Festplatte und skaliere diese mit "progressive bilinear scaling" um das Programm responsive zu halten werden die einzelnen Skalierungen in die Worker Queue des ThreadPoolExecutors eingereiht. Jedenfalls funktioniert alles noch wunderbar, wenn ich ca. 50 Bilder auf diesem Wege importiere (ca. 180Mb), sobald ich es aber mit 60-70 Bildern mache (ca.230Mb) fliegen die ganze Zeit diese OutOfMemoryExceptions.

Hier falls interessant noch der Code der tatsächlich in den WorkerThreads ausgeführt wird.
(alles was hier aus der Klasse GraphicsUtilities kommt, ist aus dem SwingX Projekt, wobei die "createThumbnail" Mehtode den Progressive Bilinear Scaling Algorithmus implementiert)

Java:
	protected void generatePreview() {
		log.log(Level.INFO, "generating new thumbnail for " + name);
		loadImageFileFromDisk();		
		int widthToScaleTo = Integer.parseInt(PreferencesHandler.getInstance().getProperties().getProperty(Constants.PROP_PREVIEW_SCALE_WIDTH));
		preview = new ImageIcon(Misc.getScaledImageInstanceFast(loadedImage, widthToScaleTo , (int) (widthToScaleTo * loadedImage.getHeight(null))/loadedImage.getWidth(null)));
	}
Java:
protected void loadImageFileFromDisk() {
		
		if(loadedImage == null && path != null) {
			log.log(Level.INFO, "loading image from hard disk " + name);
			try {
				loadedImage = GraphicsUtilities.loadCompatibleImage(new BufferedInputStream(new FileInputStream(path)));
			} catch (FileNotFoundException e) {
				log.log(Level.SEVERE, "imagefile could not be found on hard disk", e);
			} catch (IOException e) {
				log.log(Level.SEVERE, "error reading imagefile from hard disk", e);
			}
		}
	}
Java:
public static BufferedImage getScaledImageInstanceFast(BufferedImage imageToScale, int newWidth, int newHeight) {
		
		BufferedImage scaledImage;
		
		int oldWidth = imageToScale.getWidth();
		int oldHeight = imageToScale.getHeight();
		
		if(oldWidth > newWidth && oldHeight > newHeight) {
			scaledImage = GraphicsUtilities.createThumbnail(imageToScale, newWidth, newHeight);
		} else {
			scaledImage = GraphicsUtilities.createCompatibleImage(newWidth, newHeight);
			Graphics2D g2 = scaledImage.createGraphics();
			g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
			g2.drawImage(imageToScale, 0, 0, newWidth, newHeight, null);
			g2.dispose();
		}
		
		return scaledImage;
	}

Ich hoffe jemand hat ne Idee (=
Danke schonmal.

Grüße,
sMau
 
Zuletzt bearbeitet:
S

SlaterB

Gast
der Quellcode von ExecutorService/ ThreadPoolExecutor ist ziemlich offen vorhanden ohne native Methoden usw.,
inklusive Zählung, Zusammenbau der Threadnamen usw.,
ich sehe da keine praktikable Möglichkeit, über die initiale Size hinauszugehen, interessantes Phänomen,

du hast nicht zufällig noch andere ExecutorService im Programm, die verwendet werden und nicht auf 4 beschränkt sind?

hier ein Programm zur Ausgabe aller laufenden Pool-Threads einer Anwendung zu einem bestimmten Zeitpunkt,
etwa die Exception oder einfach mal so nach x sec in der Verarbeitung,
kannst du ja ausprobieren und prüfen ob 10 Thread gleichzeitig laufen oder zumindest nur z.B. Nummer 7-10
Java:
public class Test {

    public static void main(String[] args)    throws Exception  {
        ExecutorService exec = Executors.newFixedThreadPool(4);
        for (int i = 0; i < 5; i++)   {
            Runnable r = new Runnable()    {
                    public void run()    {
                        try      {
                            Thread.sleep((long)(Math.random() * 1000));
                        }  catch (InterruptedException e){  }
                    }
                };
            exec.execute(r);
        }

        Thread.sleep(1000);
        Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
        for (Thread t : map.keySet())   {
            if (t.toString().contains("pool"))  {
                System.out.println("t: " + t);
                for (StackTraceElement e : map.get(t))  {
                    System.out.println(e.toString());
                }
            }
        }

    }
}

ein anderer Schritt wäre den Quellcode komplett zu kopieren und dann einen eigenen ExecutorService mit genauen Ausgaben bei Erzeugung zu verwenden, falls dich das brennend interessiert

---------

Bilder in Java brauchen Unmengen Platz, zumindest als BufferedImage,
10 MB pro 1 MB auf der Festplatte kannst du locker überschlagen, wenn du noch ein zweites jeweils renderst, dann wieder das Doppelte usw.,


bei solchen Anforderungen, selbst wenn es nur die Original 180-230MB der Platte wären, selbst wenn nicht alle gleichzeitig verarbeitet
(bedenke aber dass die Bilder alle im Speicher bleiben, falls Attribute und die Tasks alle in einer Liste gespeichert sind),
muss man grundsätzlich mit zu wenig Speicher rechnen, du schreibst nicht einmal, ob du den Standard von Java (auf 64 MB beschränkt) erhöht hast,
falls du davon ausgehst, dass x GB installierten Arbeitsspeicher automatisch verwendet werden, würde es wiederum passen mit der Verwunderung

schreiben schreiben schreiben (so muss ich es tun ;) )
 
Zuletzt bearbeitet von einem Moderator:

sMau90

Aktives Mitglied
Hey,
Danke für die Antwort. Also bei dem Test Code den du gepostet hast, laufen genau 4 Threads, so wie es soll. Aber ich glaube ich weiß auch wie diese hohen Zahlen bei den Threadnummern zu Stande kommen. In der Doku vom ThreadExecutor steht, dass falls sich ein Thread mit ner Exception beendet wird dieser durch einen neuen ersetzt. Ich nehme an, da bei mir ja gleich öfter OutOfMemoryExceptions geworfen werden in den Threads, werden diese durch neue ersetzt und kriegen aber eben die nächste freie Nummer bei der Nummerierung.
Ich hab den zur Verfügung stehenden Speicher nicht erhöht, das werde ich mal machen, hatte ich gar nicht mehr dran gedacht.
Trotzdem wird das Problem bei entsprechend vielen Bildern wieder auftreten, denke ich oder sehe ich das falsch? Das Problem ist, die Bilder sollen schnell verfügbar sein, daher liegen sie skaliert als BufferedImage in einer Liste. Muss ich mir da jetzt einfach ein intelligenteres Caching überlegen, als einfach alles im Speicher zu halten? Oder gibt es vielleicht eine andere Möglichkeit da noch etwas zu optimieren?

Grüße,
sMau
 
S

SlaterB

Gast
grummel, natürlich die Exceptions..

zu den Bildern gibts sicher ne Menge zu sagen, aber eigentlich möchte ich da nicht zu sehr ins Detail gehen, durch Lücken auffallen ;)
paar Punkte aber zumindest genannt:
- genauer untersuchen, wieviel Speicher benötigt wird,
- skaliertes Bild vielleicht zu behalten, aber Original nicht? auf null falls in Attribut vorhanden
- Bilder wieder speichern, in der Tat, vielleicht BufferedImage als Objekt serialisieren noch schneller einzulesen als andere Varianten

vielleicht neues Thema, das bisherige läßt im Titel nichtmal vermuten dass es um Bilder in Java geht
 

sMau90

Aktives Mitglied
Ja stimmt ist vielleicht keine schlechte Idee. Also mit mehr Speicher wirds besser, aber ich kann den Speicher immer noch problemlos sprengen :D
Also muss ich wohl bei den Bildern mal ordentlich optimieren. Ein neues Thema ist dann wahrscheinlich keine schlechte Idee, falls ich da nicht weiter komme. Und danke für die Tips.

Grüße,
sMau
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
E Threads ThreadPoolExecutor remove mit callable Objekte Allgemeine Java-Themen 3
Dit_ ThreadPoolExecutor | Die Aufgaben sollen reihe nach bearbeitet werden Allgemeine Java-Themen 6
brunothg ThreadPoolExecutor anhalten Allgemeine Java-Themen 4
S ThreadPoolExecutor: wie stelle ich fest dass meine Threads im Pool mit ihrer Arbeit fertig sind? Allgemeine Java-Themen 3
T ThreadPoolExecutor Allgemeine Java-Themen 6
O ThreadPoolExecutor Allgemeine Java-Themen 2
O Unterschied zwischen ThreadPoolExecutor und Executor Service Allgemeine Java-Themen 7
javamax2000 Sehr sonderbares Verhalten Allgemeine Java-Themen 6
kodela Unterschiedliches Verhalten von BufferedReader Allgemeine Java-Themen 3
J Unvorhersehbares Verhalten - benutze ich die falsche Bedingungsprüfung oder brauche ich Threads? Allgemeine Java-Themen 12
N Best Practice Allgemeines Verhalten für ein Interface implementieren? Allgemeine Java-Themen 7
Thallius Merkwürdiges Verhalten von Swingworker.cancel() Allgemeine Java-Themen 2
T Merkwürdiges Thread-Verhalten Allgemeine Java-Themen 6
Tommy Nightmare Merkwürdiges Verhalten bei der Datenzuweisung Allgemeine Java-Themen 4
F JTable Pfeiltasten-Verhalten Allgemeine Java-Themen 1
Thallius Swing Merkwürdiges Verhalten beim Panel Tausch Allgemeine Java-Themen 3
W LocalDateTime Verhalten unerklärlich Allgemeine Java-Themen 1
Thallius Merkwürdiges StringBuilder verhalten (Char Encoding) Allgemeine Java-Themen 6
C Unterschiedliches Verhalten Editor und deployte Application Allgemeine Java-Themen 3
A Java Verhalten bei parallelem Aufruf derselben Methode?? Allgemeine Java-Themen 2
P Applet-Zugriffsrechte: merkwürdiges Verhalten Allgemeine Java-Themen 4
M Threads Viele Aufrufe aus Thread, komisches Verhalten Allgemeine Java-Themen 8
S getChildAt() Verhalten Allgemeine Java-Themen 4
S Frage zu Threads (Sichtbarkeit und Verhalten) Allgemeine Java-Themen 11
R Merkwürdiges Verhalten der equals Method Allgemeine Java-Themen 4
1 Collections Generics, internes Verhalten Allgemeine Java-Themen 16
S Collections Unverständliches Verhalten... Allgemeine Java-Themen 4
M Nach Programmdurchlauf werden Zeichen falsch dargestellt + Anderes Verhalten unter Windows Allgemeine Java-Themen 6
C Komisches Verhalten zwischen Set und List bei contains Allgemeine Java-Themen 6
S (Doppel)Klick-Verhalten vom Desktop unter Java imitieren. Allgemeine Java-Themen 5
A Seltsames Verhalten von JUnit-Tests im Zusammenspiel mit Ant Allgemeine Java-Themen 6
S Verhalten von System.getenv() in Ubuntu / Linux Allgemeine Java-Themen 12
hdi Verhalten bei nicht behandelten Exceptions Allgemeine Java-Themen 2
J Rätselhaftes Verhalten von Collections Allgemeine Java-Themen 5
M Unerklärliches Verhalten bei Variableninitialisierung Allgemeine Java-Themen 11
S Verhalten der Klasse TreeSet... Allgemeine Java-Themen 4
S Jar und Exe verhalten sich unterschiedlich unter Vista Allgemeine Java-Themen 8
M Seltsames Verhalten eines StringReaders Allgemeine Java-Themen 2
spacegaier HeapSpace der VM ändern -> Verhalten von JARs und EXEs Allgemeine Java-Themen 10
M merkwürdiges Verhalten von JUnit4 Allgemeine Java-Themen 2
M JList seltsames verhalten. Allgemeine Java-Themen 5
K Seltsames Verhalten von byte[] und Strings Allgemeine Java-Themen 6
S Seltsames Verhalten von split() Allgemeine Java-Themen 3
K Überschreiben von 'static'-Methoden hat anderes Verhalten? Allgemeine Java-Themen 2
A Streams: merkwürdiges Verhalten Allgemeine Java-Themen 7
A Streams - merkwürdiges Verhalten Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben