Deklarierung frisst Rechenzeit

javampir

Bekanntes Mitglied
hallo alle zusammen,
ich habe eine frage, die vermutlich richtung memory management bei der jvm geht. in meinem programm verursacht
Java:
short[][] ret = new short[(b.length - offset) / (numchannels * (bitspersample / 8))][numchannels];
einen merklichen zeitverlust (ca. 4 sekunden), wobei man von der größenordnung her
Java:
short[][] ret = new short[11080700][2];
hat (plus minus paar millionen). ich sehe dann auch einen vollausschlag bei der cpu. allerdings werden danach erst werte reingeschrieben, das geht dann ruck zuck in wenigen millisekunden. ich habe mit System.getCurrentTimeMillies diese zeile als übeltäter identifiziert.
gibt es ideen, wie man hier den heap bescheunigen könnte?
javampir
 

Dompteur

Top Contributor
War nur eine Idee.
Ich habe einfach einmal angenommen, dass das nicht gleich beim Programmstart passiert. Dann kann die Anforderung eines größeren Speicherblocks dazu führen, dass Java erst einmal den Speicher aufräumen muss.
 

javampir

Bekanntes Mitglied
ah, ok das kann sein. es passiert in der tat erst viel später.
was kann man da tun? ich kann ja nicht mal ne progressbar hinhauen.
 

Dompteur

Top Contributor
Als erstes kannst du einmal den Garbage Collector beobachten. Ruf dein Java-Programm mit folgender Option auf "-verbose:gc".
Da siehst du dann unter anderem die Zeitdauer der einzelnen Aufrufen. Das sollte reichen, um den Verdacht zu bestätigen bzw. zu widerlegen.

Vermeiden kannst du GC nicht.
Wenn du das Optimieren willst, dann kannst du dir hier ein paar Tips holen: http://www.cubrid.org/blog/dev-platform/how-to-tune-java-garbage-collection/
 

InfectedBytes

Top Contributor
das Problem ist die dimensionierung des Arrays.
Java:
short[][] ret = new short[11080700][2];
Intern werden quasi 11080700 viele Arrays erzeugt, welche jeweils aus 2 Einträgen bestehen. Das ist natürlich unglaublich rechenintensiv.
Wenn du unbedingt ein 2D array brauchst, dann tausche (wenn möglich) die dimensionen:
Java:
short[][] ret = new short[2][11080700];
Dadurch werden nur zwei Arrays erzeugt, welche jeweils 11080700 viele Einträge beinhalten.
Oder noch besser, nutze nur ein ein dimensionales Array mit doppelter länge
 

Bitfehler

Bekanntes Mitglied
Mal eine Zwischenfrage:
Warum vermutest du den GC als Ursache?
Der GC räumt doch nicht mehr benutzte/referenzierte Objekte im Speicherbereiche des Heap frei. Durch den GC wird folglich Speicher wieder freigeben. Da ich in dieser Diskussion aber noch nichts von java.outOfMemory gelesen habe, kann doch erstmal davon ausgegangen werden das ausreichend HeapSpace zur Verfügung steht.

Zurück zum Thema:
  1. Was sind denn deine Werte für -Xms und -Xmx?
    Kann es sein, dass du soviel Speicher anforderst, dass der initial bereitgestellte Speicherbereich dauernd erweitert werden muss und dieser Vorgang Zeit kostet? (Testweise: Xms=Xmx=max. 1/4 deines RAM)
  2. Hierbei bin ich mir selber nicht ganz sicher, also mit sehr viel Vorsicht zu genießen.
    Nehmen wir mal an, dass es wirklich etwas mit dem Heap (und dem umzu) zu tun hat, ändert sich etwas wenn das Array static ist, damit es evtl. in einem anderen Speicherbereich (nicht in Eden-Space) erzeugt wird. Alternativ kann man einen HeapDump erzeugen, um zu ermitteln, wie der HeapSpace genutzt bzw. belegt ist. Ob das einfach zu analysieren ist oder überhaupt etwas bringt, kann ich dir nicht sagen (da bisher nur einmal gemacht).
Viel Spaß noch dabei ;9
 

Tobse

Top Contributor
Kannst du vllt auch mit einem Array dieser Art arbeiten?

Java:
short[][] ret = new short[2][11080700];

Ich vermute mal ins Blaue hinein, dass das schneller geht.

Es sind letztlich auch nur ~50MB, das sollte für die JVM eigentlich kein Problem sein....
 

InfectedBytes

Top Contributor
Es sind letztlich auch nur ~50MB, das sollte für die JVM eigentlich kein Problem sein....
Das Problem ist nicht der Speicherverbrauch, sondern die Anzahl der Allokationen. Die JVM allokiert eben pro Array speicher. Wie lang dieses Array dabei ist, macht jedoch keinen Unterschied.
Dementsprechend macht es eben einen extremen Unterschied, ob man mehrere millionen Speicherallokationen hat oder eben nur zwei^^
 

Tobse

Top Contributor
Das Problem ist nicht der Speicherverbrauch, sondern die Anzahl der Allokationen. Die JVM allokiert eben pro Array speicher. Wie lang dieses Array dabei ist, macht jedoch keinen Unterschied.
Dementsprechend macht es eben einen extremen Unterschied, ob man mehrere millionen Speicherallokationen hat oder eben nur zwei^^
Das ergibt Sinn, ja :D

Habe das jetzt getestet und InfectedBytes' und meine Vermutung hat sich bestätigt:

Java:
long a = System.currentTimeMillis();

short[][] ret = new short[2][11080700];

long b = System.currentTimeMillis() - a;

System.out.println("[2][XXX]: " + b + "ms");

a = System.currentTimeMillis();

short[][] ret2 = new short[11080700][2];

b = System.currentTimeMillis() - a;

System.out.println("[XXX][2]: " + b + "ms");

Code:
[2][XXX]: 10ms
[XXX][2]: 3137ms
-------------------
[2][XXX]: 9ms
[XXX][2]: 3365ms
-------------------
[2][XXX]: 9ms
[XXX][2]: 3254ms
 

javampir

Bekanntes Mitglied
danke!!
ich habe das array mal umgedreht, und tatsächlich, geht wie geschmiert.
ich kann leider nicht ein einzelnes array draus machen, denn wenn statt der 2 ne 4 dasteht und ich ein paar millionen mehr drin hab, bin ich sofort im int overflow bei den indizes der arrays drin.

Vielen Dank euch allen!
 

InfectedBytes

Top Contributor
"ein paar millionen mehr" reichen da nicht aus. Bisher bist du bei rund 11 millionen, damit es zum overflow kommt, musst schon mehr als 2 milliarden mehr haben ;-)
 

Tobse

Top Contributor
"ein paar millionen mehr" reichen da nicht aus. Bisher bist du bei rund 11 millionen, damit es zum overflow kommt, musst schon mehr als 2 milliarden mehr haben ;-)
Richtig. Und selbst bei zwei Dimensionen: solange du die kleinere Zahl (dem ersten Code zu entnehmen die Zahl der Kanäle) in der ersten Dimension hast, wird die Zeit für die Speicherreservierung auch nie über ~20-30ms steigen.
 

javampir

Bekanntes Mitglied
ok, war nur aus dem handgelenk geschrieben. aber es sind (unschwer zu erraten) audiodateien mit raw data, die können auch größer werden. aber das sind dann insgesmt memorygeschichten
 

RalleYTN

Bekanntes Mitglied
Und warum? Die größten FLAC und WAV Dateien, die ich je gesehn habe waren bei 100-200MB. Bei zT. 4 - 8GB Arbeitsspeicher ist das absolut 0 Problem.
Allerdings nehmen die dann die dann diese 100-200MB weg und der Java Heap Space ist ja nicht genauso groß wie der Arbeitspeicher. Am performantesten ist es jede Datei nur dann zu laden wenn man sie brauch und wenn sie einmal nicht mehr gebraucht wird dann schließt man den Datenstrom wieder. Der einzige Nachteil dabei ist, das etwas Zeit benötigt um die Datei zu laden.
 

JStein52

Top Contributor
Das kann man doch so allgemein nicht sagen. Das hängt davon ab was er mit seinen Daten macht. Wenn er ständig auf alle Kanäle zugreifen muss kann er sie eben nicht immer wieder neu laden. Und es hängt davon ab wie seine Anwqendung genutzt wird. Von einem Benutzer auf einem einzelnen Rechner, da wäre es zum Beispiel kein Problem wenn er sich grosse Teile seines Speichers voll lädt. Oder von vielen Benutzern auf einem Terminalserver, dann könnte das zu einem Problem werden.
 

Tobse

Top Contributor
Das kann man doch so allgemein nicht sagen. Das hängt davon ab was er mit seinen Daten macht. Wenn er ständig auf alle Kanäle zugreifen muss kann er sie eben nicht immer wieder neu laden. Und es hängt davon ab wie seine Anwqendung genutzt wird. Von einem Benutzer auf einem einzelnen Rechner, da wäre es zum Beispiel kein Problem wenn er sich grosse Teile seines Speichers voll lädt. Oder von vielen Benutzern auf einem Terminalserver, dann könnte das zu einem Problem werden.
So sehe ich das Auch. Audio-Bearbeitungs Software hat bei mittelgroßen Projekten locker mal 10-20 Spuren im RAM (undzwahr in 48Khz, 64bit Qualität). Die JVM macht dne Heap auch größer, wenn mehr RAM gebraucht wird.
Auf einem Server ist das natürlich wieder anders. Aber wenn der Server Audiodaten verarbeiten muss, ist es unumgänglich, einiges an Daten im RAM zu haben (z.B. SoundCloud, YouTube, Voice-Chats).
 

javampir

Bekanntes Mitglied
ich muss immer wieder auf die daten zugreifen. ich lade hier nicht mehrere audioströme. nur mal zum spaß: der herr der ringe soundtrack als wav hat ca. 3 GB
es ist als desktopanwendung konzipiert, mit zentral im netz verwaltetem speicher muss ich mir keine sorgen machen.
 

Ähnliche Java Themen

Neue Themen


Oben