Действительно ли 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, результат возвращается из первого сравнения.