Gleiche Operation dauert teilweise sehr lange

twinflyer

Mitglied
Guten Abend alle miteinander,
ich hab erst vor kurzem im Grafikprogrammierungsunterforum (was für ein Wort) ein Thema eröffnet, wo es darum ging ein Bild richtig zu drehen, dass es auch in der Größe passt. Das Thema ist durch, dann gings ans optimieren. Ich hab gemerkt, dass das ganze relativ langsam ist (jedenfalls zu langsam um es in einem Spiel für viele rotierende Objekte nutzen zu können) hab ich den Code abgeändert.
Jetzt bekomme ich ein 300x300 Pixel großes Bild in ca. 1.49071 ms gedreht. viel größer werden die Bilder später eh nicht sein, von daher ist das OK.
Ich hab in der Animation immer wieder kleine Ruckler gesehen, und weil ich keine Ahnung hatte (und immernoch nicht habe) wo die her kommen hab ich mal die Zeiten gemessen, die es braucht um das Bild zu drehen:

Java:
	public Image getImage() {
		long t = System.nanoTime();
		BufferedImage img = (BufferedImage) icon.getImage();
		
		//First calculate the new ImageSize
		int size = (int) Math.sqrt( Math.pow(img.getWidth(), 2) + Math.pow(img.getHeight(), 2));
		
        //create a new (empty) Image to hold the finished rotated Image.
		BufferedImage rotatedImage = new BufferedImage(
									size,
									size,
									BufferedImage.TYPE_INT_ARGB);
		Graphics2D g2d = (Graphics2D) rotatedImage.getGraphics();
		g2d.setColor(Color.BLACK);
		g2d.drawRect(0, 0, size-1, size-1);
		int w = img.getWidth();
		int h = img.getHeight();
		int a = size / 2;
		
		//Rotate g2d
		AffineTransform rotation = g2d.getTransform();
		rotation.rotate(Math.toRadians(degree), a, a);
		g2d.setTransform(rotation);
		
		//Calculate where the rotated Image has to be painted to be centered
		int x = (size-img.getWidth())/2;
		int y = (size-img.getHeight())/2;
		
		//Draw the original image rotated to the new BufferedImage
		g2d.drawImage(img, x, y, w, h, null);
		g2d.dispose();
		//System.out.println(rotatedImage.getWidth());

		degree += speed;
		if (degree % 360 == 0)
			degree = 0;
		System.out.println(((float) (System.nanoTime() - t) / 1000000));
		return rotatedImage;
	}

Hier der Code, der das Bild dreht. Am Ende wird noch die benötigte Zeit in Millisekunden ausgegeben.
Code:
getImage()
Wird alle 20ms von einem Thread aufgerufen (nicht der EDT).
Die Zeiten hab ich aus der Konsole in ein Tabellendokument kopiert und mir die Werte mal genauer angeschaut.
Das Dokument findet ihr hier: Tabelle

Beachtet auch die anderen Sheets. Da findet man noch ein paar Diagramme die das ganze schöner veranschaulichen.
Kann mir vielleicht jemand verraten wo diese extremen Ausschläge herkommen? Immerhin liegen die gerade bei den kleineren Grafiken in einer mir nicht erklärbaren höhe.
Danke für eure Hilfe :)

Gruß Max
 
Moin.
Sofern das Operationen sind, die auf der CPU stattfinden (kenne mich im 3D bereich nicht so super aus!), kann ich mir vorstellen, dass in regelmäßigen Abständen der Scheduler dazwischenhaut und die CPU an anderen Prozessen arbeiten lässt.
Die Zahl der Ausreißer steigt mit der Größe der Bilder und somit mit der Dauer der durchschnittlichen Bearbeitungszeit.

Je länger der Prozess dauert, desto wahrscheinlicher ist es, dass der Scheduler dich unterbricht. Bei den maximal großen Bildern in deiner Übersicht ist es ja die Regel und nicht mehr die Ausnahme.

Nur ne Vermutung.

Grüße!
 

Lumaraf

Bekanntes Mitglied
Ich vermute die Hänger kommen von der Garbage Collection. Starte dein Programm am besten einfach mal mit dem VM Parameter -verbose:gc um zu sehen wann die GC läuft und wie lange sie braucht.
 

Landei

Top Contributor
Wenn es nicht allzu viele, allzu große Bilder sind, und Ein- oder Halb-Grad-Schritte reichen, würde ich alle Drehungen vorberechnen und in einem Array speichern. Da hast du vielleicht am Anfang eine leichte Verzögerung, und dafür sollte der Rest trotz GC flüssig laufen..
 

Marco13

Top Contributor
Ich habe schon oft und viel darüber gelesen, was der GC doch für ein Performancefressendes Monster ist.... meist zu Unrecht. In diesem Fall könnte es zumindest teilweise stimmen. Ich vermute mal, dass (fast) jedes mal, wenn neu gezeichnet werden soll, mit dieser Methode ein neues Bild erstellt wird. Wozu? Man kann Bilder auch gedreht zeichnen.
(BTW: Schau' dir mal http://www.emaggame.com/ an - z.B. den Test '10000 Sprites' oben links)
 

twinflyer

Mitglied
Danke für die Zahlreichen antworten.
Besonders an Lumaraf. Du bringst es auf den Punkt. Es liegt also höchstwahrscheinlich am GC. Die neuesten Werte sehen (etwas gekürzt) folgendermaßen aus:


Code:
1.019958
1.209101
1.014312
1.178329
[GC 10936K->7406K(15936K), 0.0002560 secs]
1.536853
1.798829
1.132314
1.342629

#Alles normal hier

1.102672
0.962932
1.133161
0.963215
1.143324
0.969426
1.154616
[GC 15128K->11600K(16640K), 0.0003453 secs]
[Full GC 11600K->3171K(16640K), 0.0144081 secs]
16.012178
16.32525
0.936679
1.089687
0.981282
1.189057
0.926234
1.075572
1.000761
1.248623
0.919458
1.067949
[GC 7401K->4577K(15936K), 0.0003667 secs]
1.360696
1.559437
0.942324
1.163649
1.006407

#Alles normal hier

1.219545
1.031532
1.193856
1.020522
1.172118
[GC 15128K->11600K(16640K), 0.0003413 secs]
[Full GC 11600K->3171K(16640K), 0.0144457 secs]
16.168291
16.47854
1.056657
1.29125

#Alles normal hier

1.294073
[GC 7401K->4577K(15936K), 0.0003676 secs]
1.475594
1.64808
1.0129
1.162802

Es wird deutlich, dass immer nach
Code:
[Full GC 11600K-> .......
die Berechnungsdauer hoch geht (Der GC braucht hier dann auch ca. 14ms).
Kann ich dem GC nicht irgendwie sagen wann er leeren soll? Immerhin schläft der Thread immer 20ms. Können die nicht irgendwie für den GC genutzt werden?
Irgendwie muss ich das doch vermeiden können.

Was noch wichtig ist:
Ich habe das rendering geändert. Anstatt immer ein neues BufferedImage zu erzeugen übergebe ich nun das Graphics-Object und zeichne das gedrehte direkt. Außerdem benutze ich einen doppelten FrameBuffer (
Code:
createBufferStrategy(2)
) und demnach auch ActiveRendering.

Bitte helft mir das Problem zu lösen. Ich möchte keine fertige Lösung, lieber einen Denkanstoß in die richtige Richtung. Wenn ich mich selbst einlese behalte ich die Dinge einfach besser und von Copy & Paste lerne ich garantiert nichts!

Gruß twinflyer

PS.: Eigentlich wollte ich die Daten in einen Spoiler packen, aber der Spoiler-Tag wurde einfach in Klartext ausgegeben :/

[EDIT]
Habe gerade einen kleinen Versuch gestartet.
Wenn ich immer nach dem Rendern (also kurz bevor der berechnende/zeichnende Thread für 20ms schläft)
Code:
System.gc()
in einem extra Thread aufrufe bekomme ich die Peaks von 18.46 auf 4.43 Millisekunden gedrückt. Auch die Durchschnittliche Berechnungsdauer sinkt um fast 0.1ms.
Die genauen Werte findet ihr hier bei "TESTAREA": Tabelle
Das kann aber nicht die feine Englische art sein. Wirkt auf mich eher gewaltsam dazu gezwungen.
Was haltet ihr davon?
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Lass das mit dem System.gc().

Ist der GC immernoch ein Problem, jetzt wo nicht 50 neue Bilder Pro Sekunde erstellt werden? ( :autsch:)
 

Marco13

Top Contributor
Der Link ist für den einen oder anderen sicher Interessant, aber ... wie viele Spiele laufen vernünftig, OHNE dass man den Wert von "-XX:CMSIncrementalDutyCycleMin" von 10 auf 15 erhöht?

In diesem Fall sollte es schon helfen, zu vermeiden, jede Sekunde 50 neue Bilder zu erstellen. Dass man nicht 20ms warten sollte, sondern so lange, wie man warten muss, um eine konstante Framerate zu erzielen, kommt dann noch dazu.
 

twinflyer

Mitglied
Super, danke für eure Tipps.
Das rendern lass ich jetzt erstmal so wie es ist. Immerhin handelt es sich momentan nur um eine Vorschau einzelner Szenerie Objekte. Das Spiel selbst werde ich mir vornehmen, sobald ich auch unter realen Bedingungen testen kann. Sprich: sobald ich die Karte mit Objekten befüllen kann.

Die Sache mit dem GC werde ich mir auf jeden Fall noch genauer anschauen. Kann ja nicht schaden sich in das Thema mal einzulesen.

Gruß Max
 

twinflyer

Mitglied
@bone2
Ist schon implementiert und hat ordentlich Geschwindigkeit gebracht ;)
Ich weiß auch nicht warum ich da nicht von Anfang an drauf gekommen bin. War wahrscheinlich eine übermüdete Nacht session^^
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
bueseb84 Gleiche Maven Versions in Child Modulen Allgemeine Java-Themen 13
parrot Gleiche Buchstaben Aufage Allgemeine Java-Themen 40
M ZipOutputStream gleiche Datei andere Größe? Allgemeine Java-Themen 0
R Gleiche Objektreferenz trotz clone()? Allgemeine Java-Themen 12
turmaline OOP zwei gleiche Methoden mit kleinen Unterschieden Allgemeine Java-Themen 15
G Gleiche Packages in verschiedenen JAR Dateien - Welches Package wird verwendet? Allgemeine Java-Themen 5
M HashSet<String> das selbe oder das gleiche? Allgemeine Java-Themen 4
J Gleiche Packagestruktur in zwei *.jar Dateien Allgemeine Java-Themen 4
M Die gleiche Klasse in mehreren JAR files Allgemeine Java-Themen 5
B Liste auf gleiche Elemente untersuchen? Allgemeine Java-Themen 2
V String formatiert ausgeben ( gleiche Anzahl von Ziffern ) Allgemeine Java-Themen 5
E ArrayList referenziert immer auf das gleiche Objekt Allgemeine Java-Themen 2
J WARNING: An illegal reflective access operation has occurred, beim Compilieren von JasperReports, was bedeutet das ? Allgemeine Java-Themen 23
M Methoden Operation auslagern und "nebenbei" laufen lassen Allgemeine Java-Themen 3
B JUnit Zufalls Operation testen Allgemeine Java-Themen 1
C AES addRoundKey Operation mit 192 Bit bzw 256 Bit Schlüssel Allgemeine Java-Themen 2
G Unchecked/Unsafe Operation Allgemeine Java-Themen 8
J Threads HTTP Request (Thread) dauert lange - in Android Allgemeine Java-Themen 3
M Fasta nach Mustern durchsuchen dauert zu lange Allgemeine Java-Themen 2
H Webstart...Start dauert ewig... Allgemeine Java-Themen 5
A testen ob Primzahl dauert bei größeren zahlen extrem lange Allgemeine Java-Themen 8
M Wie lange dauert ein garbage collection Allgemeine Java-Themen 7
sokobus java ältere Version - das laden dauert sooo lange Allgemeine Java-Themen 3
D FileOpenDialog dauert 23 Sekunden bis zur Anzeige Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben