23 Nov 2006, 11:10

Java Strings oder Wie-ich-meine-Perfromance-verbaue

Share

Kürzlich musste ich feststellen, dass es keine gute Idee ist eine größere Menge an Daten in einem String zu puffern. Ich finde es etwas schwierig zu umschreiben aber so sieht der Beispiel-Code aus:

String str = ""
while((buffer = br.readLine() != null) {
  str += buffer;
}
return str;

Das Problem an dieser Konstruktion ist, dass bei jedem Schleifendurchlauf - und das waren in dem Fall einige - jede Menge Objekte anglekt werden. Für die + Operation zwischen Strings (Konkatenation) wird von Java in etwa folgener Code generiert:

str = new StringBuilder().append(str).append(buffer).toString();

Eventuell wird das interne Char-Array des StringBuilders beim zweiten append nochmal vergrößert, d.h. ein neues anlegen, das halt hineinkopiert, das alte löschen. Dabei muss eine Menge Speicher allokiert und wieder freigegben werden, jeden Menge neue Objekte werden erzeugt, sprich: es entseht ein riesiger Overhead. Das kommt insbesondere dann zum tragen wenn die der BufferReader br gerade dabei ist eine Textdatei von vielleicht 5MB einzulesen, z.B. Base64 kodierte Binärdaten. Die ganze Operation hat so je nach System ca. 10-120 Minuten benötigt.

Einen kleinen Tipp und ein paar Änderungen später hat das ganze nur noch ca. 1,2 Sekunden benötigt. Der oben genannte Code wurde einfach in folgendes geändert:

StringBuilder sb = new StingBuilder()
while((buffer = br.readLine() != null) {
   sb.append(buffer);
}
return sb.toString();

Da hier der StringBuilder direkt benutzt wird, ergibt sich ein beachtlicher (!) Performanz-Gewinn.