Pull to refresh

Строковые классы Java. Сравнение производительности

Java *
Никогда не задавались вопросом насколько собственно отличается производительность строковых классов Java?

В данном топике я попытался сравнить производительность java.lang классов String, StringBuilder и StringBuffer.


Очевидные факты



Не секрет, что в Java существуют три основных класса для работы со строками. Основной класс, который мы чаще всего используем в программах, это String. Особенностью данного класса является то, что он создает неизменяемые строки. Т.е. какой строкой символов мы объект при создании инициализировали, такой она и останется. Поэтому конструкция:

String st = "Маша";
st += "Саша";

Создаст новый объект содержащий строку «МашаСаша» а исходные объекты будут уничтожены сборщиком мусора.

Если операций конкатенации над одним и тем же строковым объектом производится много, это приводит к интенсивному процессу порождения новых объектов и добавляет работы сборщику мусора.

Если нам нужны изменяемые строки, разработчики нам предлагают другие классы. Первый, который был в Java изначально — StringBuffer и более новый StringBuilder (появился начиная с версии 1.5). Как пишут в документации, StringBuffer — безопасно применять в многопоточных приложениях, но второй более эффективен.

Чего хочется



Ну более эффективен, менее эффективен, этот конечно хорошо, но хочется цифр. Ведь иной программист может подумать, а стоит ли использовать «неудобные» StringBuffer/StringBuilder вместо такого замечательного String ради экономии пары милисекунд? Другие скажут, что не бывает таких ситуаций, когда нужно выполнить ну, скажем, сто тысяч конкатенаций… Но любопытно же, велика ли разница?

Тест



Читаем строки из текстового файла «onegin.txt» (призовем на помощь классика). Файл имеет размер 297463 байта, utf-8, 27195 слов. Сложим все слова файла в одну строку с использованием всех трех классов и сравним производительность. Чтоб было интереснее, проведем тест на разных JVM и в двух OS. Linux (я использую LinuxMint 9 это такой разукрашенный Ubuntu, если кто не знает) ну и Win XP Pro SP3. Обе операционки 32-битные, ибо пишу я с нетбука с Atom N280. Но мы же не рекорды ставим, нам важна тенденция.

Собственно сама программа, проще некуда:
package stringtest1;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

public class Main {

  public static void main(String[] args) throws FileNotFoundException, IOException {

   BufferedReader reader = new BufferedReader(new FileReader("onegin.txt"));

   StringBuilder sb = new StringBuilder();
   String line = null;
   while ( (line = reader.readLine()) != null) {
     sb.append(line).append("\n");
   }
   reader.close();
   String[] words = sb.toString().split("\\s+");
   System.out.println("Total words:" + words.length);
   waitEnter();

   long ts = System.nanoTime();

   String buff = "";
   //2 StringBuffer buff = new StringBuffer();
   //3 StringBuilder buff = new StringBuilder();

   for (String word : words) {
    buff += word + " ";
    //2&3 buff.append(word).append(" ");
   }

   long te =System.nanoTime();

   System.out.println("Complete, lenght:" + buff.length() + " elapsed time:" + (te - ts)/1e6 + "ms");

  }

  private static void waitEnter() {
   Scanner scan = new Scanner(System.in);
   System.out.print("Press Enter key.");
   scan.nextLine();
  }

}

* This source code was highlighted with Source Code Highlighter.


Варианты для StringBuffer и StringBuilder аналогичны, и отображены в комментариях.
Замеры времени работы каждого варианта для каждой виртуальной машины производились 5 раз и вычислялось среднее значение.

Результаты


Linux

Класс Open JDK 1.6.0_18 HotSpot 1.6.0_20 JRockit 4.0.1
String 27390ms 26850ms 26940ms
StringBuffer 35.55ms 34.87ms 15.41ms
StringBuilder 33.01ms 31.78ms 12.82ms

Windows XP

Класс HotSpot 1.6.0_20 JRockit 4.0.1
String 55260ms 45330ms
StringBuffer 19.38ms 14.50ms
StringBuilder 16.83ms 12.76ms


Выводы


Если нам нужны модифицируемые строки, используем StringBuffer (в многопоточных приложениях) и StringBuilder в остальных. Разница весьма ощутима.

Понятно почему JVM от Open JDK немножко отстает, что-то там Sun или уже Oracle подкрутил. Не совсем понятно, почему такая большая разница в работе с объектами класса String под Linux и WinXP. Толи Win не дает JVM работать так же эффективно как Linux, то ли это особенности реализации JVM… Тут нужно копать дальше.

Для справки:
JRockit — это виртуальная машина от Oracle.
HotSpot — это машина изначально разработанная Sun, теперь само собой куплена Oracle.
Open JDK — Open-source JDK основаная на исходниках в свое время открытых Sun-ом.
Tags:
Hubs:
Total votes 53: ↑42 and ↓11 +31
Views 34K
Comments Comments 78