Действительно ли String.intern() действительно повышает производительность?

Я провел небольшое исследование, чтобы узнать, как метод String.intern() реализован в java.

Я посмотрел на С++ реализацию Intern Pool из Open JDK 6, и там я увидел простой HashSet. Для меня это означало, что когда кто-то пытается ставить a String, следующие шаги должны быть выполнены:

  • поиск хеш-кода, связанного с данным String
  • поиск соответствующего ведра
  • сравнение данной строки со всеми другими строками в ведре. До этого шага может быть 0 строк, одна строка или LOT OF Строки в ковше. Итак, если данная строка была ранее поместите в ведро мы получим хотя бы одно сравнение (что лучший случай. Конечно, могло быть много столкновений и теперь многие другие строки находятся в ведре)
  • Если строка была найдена в ведре, тогда она должна быть возвращен методом intern()
  • Если строка не найдена в ковше, тогда она должна быть помещена в ведро и возвращен методом intern()

Так много людей говорят, что str1.intern() == str2.intern() будет быстрее, чем str1.equals(str2).

Но я не вижу причины, по которой она должна быть быстрее.

Как я вижу в случае str1.equals(str2), мы всегда имеем две строки, сравнивающие char с помощью char в методе String.equals().

В случае str1.intern() == str2.intern(), сколько сравнений нам нужно было бы получить или поместить String в/из пула (правильно, это может быть много сравнений, и они простые char путем сравнения char слишком)?

Поэтому в случае str1.intern() == str2.intern(), даже если мы используем == для сравнения строк, у нас также будет много дополнительных действий, таких как сравнения, описанные ранее.

Когда я понял это, я решил провести несколько эталонных тестов.

Первые результаты показали мне, что str1.intern() == str2.intern() был быстрее, чем str1.equals(str2).

Такое поведение было вызвано тем, что метод String.intern() является родным, поэтому его не следует интерпретировать каждый раз, а String.equals() - это метод java.

Итак, я решил использовать параметр -Xcomp, чтобы JVM скомпилировал весь код при запуске.

После этого уровень показал лучшую скорость, чем стажер.

Я тестировал его на Java 6 и 7.

Итак, мой вопрос: вы когда-нибудь видели ситуацию, когда стажировка увеличивала скорость сравнения String? Я да, как это может быть?

Или, может быть, intern() может помочь сохранить больше свободной памяти?

Ответы

Ответ 1

String.intern() предназначен для уменьшения использования памяти.

Используйте только интернированные строки (если когда-либо), когда у вас много, много разных копий SAME String в памяти. путем интернирования строк, все эти копии будут использовать одну и ту же ссылку.

Я только видел, что интернирование строк полезно, когда у меня есть миллионы копий одной и той же строки.

Как и при любой оптимизации, делайте это только после проблемы производительности или памяти, и вы профилировали ее так, чтобы вы обнаружили, что это узкое место.

См. этот пост в блоге для получения более подробной информации о интернирования строк.

Ответ 2

На ваш вопрос о том, почему str1.intern() == str2.intern() может быть быстрее:

Это реализация String.equals() - как вы можете видеть, она может быть очень неэффективной в зависимости от сопоставленных строк.

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                        return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

Ваши шаги могут быть намного быстрее:
1) hashCode() вычисляется один раз для любой строки из-за ее неизменности и довольно быстро - 2) найти ведро O (1)
3) сравнение вашей String с другими в одном ведре - возможно, несколько, но все же должно быть быстрее, чем equals()
4) и 5) являются быстрыми

И не забывайте, что вышеприведенные операции должны выполняться только один раз для любой String, как только это будет intern() ed, результат возвращается из первого сравнения.