5 Stimmen

Java: Reduzierung des Speicherverbrauchs durch 2D-Float (Floats[][]) Arrays

Ich habe eine Java-Anwendung, die intensiv mit 2D-Float-Arrays (float[][] Arrays) arbeitet, die tatsächlich Bilder auf schwarzem Hintergrund halten. Beide Dimensionen sind gleich (quadratisch) und sind eine Potenz von 2 (meistens 256, 512, 1024), sodass die Bereiche nahe den Rändern in den meisten Fällen Nullen haben.

Die Größen, die eine Potenz von 2 sind, dienen zur Steigerung der Leistung (es gibt eine FFT) und zur Verringerung der Komplexität bei Operationen über diese Arrays wie Rotation usw. Kürzlich hatte ich auf meinem 6GB-Maschine einen Mangel an Heap für diese Anwendung. Nach meiner Berechnung sollte der Speicherverbrauch für diese Anwendung etwa 2-3GB betragen, während er 4-5GB erreicht (im Windows-Task-Manager nachgesehen). Ich habe den "YourKit"-Profiler verwendet und er zeigt an, dass diese Float-Arrays tatsächlich am meisten Speicher verbrauchen, jedoch sollte die Gesamtgröße dieser Float-Arrays grob etwa 1,3GB betragen (nun, ich weiß, dass es an der JVM liegt, wie die Daten gespeichert werden, aber ich habe nicht mit einem 2-3-fachen Unterschied im Speicherverbrauch gerechnet).

Ich habe versucht, die Daten mit dem Snappy-Kompressor auf die Schnelle zu komprimieren/dekomprimieren (und der Speicherverbrauch sinkt auf 3,5GB), aber die Leistung sinkt mehrfach, was nicht sehr akzeptabel ist. Außerdem habe ich die Leistung getestet, als ich diese floats[][] durch BufferedImage ersetzt habe, aber die Leistung war sehr schlecht.

Es gibt also 2 Möglichkeiten, die für mich funktionieren würden, um den Speicherverbrauch zu verringern: 1) Wrapper für float[][] Array schreiben, um bei "Nullen" Elementen zu sparen (es gibt viele "leere" Zeilen und Spalten) 2) von "Potenz von 2" abweichen

Beide Möglichkeiten erfordern ziemlich viel Codierung/Refactoring, daher während ich darüber nachdenke, "zu sein oder nicht zu sein" - habt ihr vielleicht eine bessere Idee zu diesem Problem, Leute?

Danke!

1voto

hotpaw2 Punkte 69093

Ein FFT erfordert ein komplexes Array, das doppelt so groß ist wie das reale Datenarray, auch wenn Sie von einem realen Array am Eingang konvertieren und am Ende wieder in ein Magnitudenarray zurückkonvertieren. Dies kann für die größere als erwartete Arbeitsspeicherverwendung verantwortlich sein.

Ein dünnbesetztes Array funktioniert nicht für eine FFT, da die Zwischenschritte in einer FFT fast immer das gesamte komplexe Array füllen werden.

Viele moderne leistungsstarke FFT-Bibliotheken, wie solche, die auf FFTW basieren, können sehr effizient mit FFT-Längen umgehen, die nicht nur Potenzen von 2 sind (eine Länge, die das Produkt kleiner Primzahlen ist, kann ziemlich effizient FFT'd werden). Dies kann viel 2D-Padding für viele Größen einsparen.

0voto

Arsen Punkte 153

Nach eingehenderer Untersuchung stellte sich heraus, dass die JVM mit den Flags "UnlockEperimentalFeatures" und "use GC1" gestartet wurde. Als Ergebnis gab es eine beträchtliche Anzahl von NICHT garbage-collected "unreachable" BufferedImage-Rastern (die byte[]-Arrays enthalten). Beim Aufruf von GC aus dem "YourKit"-Profiler wurden diese Objekte aus dem Heap entfernt (das ist natürlich keine akzeptable Methode für mich, da ich erwartet hatte, dass die JVM den Heap selbst verwaltet).

Ich möchte mich bei allen bedanken, die sich die Zeit genommen haben, mir zu helfen. Ein besonderer Dank geht an Jim Garrison (es sieht so aus, als ob ich durch das Entfernen der oben genannten Flags die Speicheranforderungen nur vorübergehend verschoben habe, aber wenn mehr Arrays ins Spiel kommen, wird das Kaufen von mehr Speicher der einfachste Weg sein, um Leistungseinbußen zu vermeiden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X