awk Speicherverlust?

11

Darauf aufbauend führe ich den Befehl aus

< /dev/urandom hexdump -v -e '/1 "%u\n"' |
awk '{ split("0,2,4,5,7,9,11,12",a,",");
       for (i = 0; i < 1; i+= 0.0001)
         printf("%08X\n", 100*sin(1382*exp((a[$1 % 8]/12)*log(2))*i)) }' |
xxd -r -p |
sox -traw -r44100 -b16 -e unsigned-integer - -tcoreaudio

Ich stelle fest, dass der von awk verwendete Speicher während der Ausführung dieses Befehls kontinuierlich wächst und beispielsweise über 500 MB Speicher verbraucht, bis 75 MB Roh-Audiodaten abgespielt wurden. Alle anderen Befehle in der Pipeline behalten eine konstante Speichermenge bei.

Wofür verwendet awk diesen Speicher und gibt es eine Alternative, bei der die beabsichtigte Stream-Verarbeitung nur eine konstante Speichermenge verwendet?


falls die awk version wichtig ist:

 awk --version
awk version 20070501

Hier ist der Befehl, den ich basierend auf der Antwort von Thomas Dickey getestet habe:

< /dev/urandom hexdump -v -e '/1 "%u\n"' |
awk 'BEGIN { split("0,2,4,5,7,9,11,12",a,",") }
           { for (i = 0; i < 1; i+= 0.0001)
               printf("%08X\n", 100*sin(1382*exp((a[$1 % 8]/12)*log(2))*i)) }' |
xxd -r -p |
sox -traw -r44100 -b16 -e unsigned-integer - -tcoreaudio
bames53
quelle
Ich sehe auch einen Speicherverlust auf meinem BSD-Darwin (Mac) -System.
Otheus
Sie sagten, Here's the command I tested...aber Sie haben vergessen, uns das Ergebnis dieser Tests mitzuteilen - hat es das Problem gelöst oder nicht? Möglicherweise nicht, da jeder Verweis auf ein Element in a[]der Schleife Einträge erstellen würde, wenn sie nicht vorhanden wären. Wenn dies nicht der Fall ist, hilft es, wenn Sie das Array vor dem Teilen oder nach der Verwendung explizit löschen, z awk '{ delete a; split("0,2,4,5,7,9,11,12",a,","); for (i = 0; i < 1; i+= 0.0001) printf("%08X\n", 100*sin(1382*exp((a[$1 % 8]/12)*log(2))*i)) }'. Bei diesem Codesegment müssen Sie split () an seiner ursprünglichen Position belassen und nicht nach BEGIN verschieben.
Ed Morton

Antworten:

11

Diese Aussage ist seltsam:

split("0,2,4,5,7,9,11,12",a,",");

Es teilt wiederholt eine konstante Zeichenfolge, um ein Array zu erstellen a. Wenn Sie das in einen BEGINAbschnitt verschieben, sollte das Programm genauso funktionieren - ohne ajedem Eingabedatensatz eine neue Kopie des Arrays zuzuweisen.

Adressieren von Kommentaren: Die for-Schleife und der Ausdruck weisen den Speicher nicht auf einfache Weise zu. Ein schneller Vergleich von mawk, gawk und awk zeigt, dass es mit den ersten beiden kein Problem gibt, aber /usr/bin/awkunter OSX leckt es schnell. Wenn Apple ein System zur Fehlerberichterstattung hätte, wäre dies der richtige Ort.

Thomas Dickey
quelle
1
Ich habe getan, was Sie auf meinem Mac vorgeschlagen haben (ich bin nicht der OP). Ich sehe immer noch ein Speicherleck mit awk.
Otheus
Irgendwie einfach Referenzierung die ein Hash - Speicher verwendet.
Otheus
Hier gilt das gleiche; Ich sehe immer noch das Gedächtniswachstum. Ich habe auch einen groben Vergleich durchgeführt und die Speichernutzung scheint mit dieser Änderung mit der gleichen Geschwindigkeit zu wachsen.
Bames53
Auch dies wird einen Speicherverlust verursachen:awk 'BEGIN { split("0,2,4,5,7,9,11,12",a,","); } { for (i = 0; i < 1; i+= 0.0001) a[1]; }'
Otheus
Sie könnten zu mawk oder gawk wechseln. Apples Basissystem enthält einige echte Antiquitäten.
Thomas Dickey
5

Hier ist ein Perl-Äquivalent, das nicht ausläuft:

perl -lne 'BEGIN { @a=(0,2,4,5,7,9,11,12);}
   for ($i = 0; $i < 1; $i+= 0.0001) {
     printf("%08X\n", 100*sin(1382*exp($a[$F[0] % 8]/12)*log(2))*$i) }'

Es ist fast identisch. $1wird ersetzt durch $F[0]und iwird ersetzt durch $i. Der Hash awird durch ein tatsächliches Array ersetzt @a.

Es ist ratsam, einige Eingaben zu generieren und die Ausgabe- und Notenunterschiede zwischen den beiden zu vergleichen. Es gibt oft Nuancen, wie interpretierende Sprachen mit Gleitkomma umgehen.

Otheus
quelle