String.intern() действительно увеличивает производительность?
Я провел небольшое расследование, чтобы выяснить, как String.intern()
Метод реализован в Java.
Я посмотрел на C++ реализацию Intern pool из Open JDK 6 и там увидел простой HashSet
, Для меня это означало, что когда кто-то пытается интернировать String
следующие шаги должны быть сделаны:
- найти хеш-код, связанный с данным
String
- найти подходящее ведро
- сравнивая данную строку со всеми другими строками в корзине. Перед этим шагом может быть 0 строк, одна строка или много строк в сегменте. Поэтому, если указанная строка была ранее помещена в корзину, мы получим хотя бы одно сравнение (это лучший случай. Конечно, могло быть много столкновений, и теперь в корзину входит много других строк).
- Если строка была найдена в корзине, она должна быть возвращена
intern()
метод - Если Строка не была найдена в ведре, тогда это должно быть помещено в ведро и возвращено
intern()
метод
Так много людей говорят, что str1.intern() == str2.intern()
будет быстрее, чем str1.equals(str2)
,
Но я не вижу причины, по которой это должно быть быстрее.
Как я вижу в случае str1.equals(str2)
у нас всегда есть две строки, сравнивающие char с char в String.equals()
метод.
В случае str1.intern() == str2.intern()
Сколько сравнений мы должны были бы получить или поместить строку в / из пула (верно, это может быть много сравнений, и они также являются простыми сравнениями по типу char)?
Так что в случае str1.intern() == str2.intern()
даже если мы используем ==
для сравнения строк у нас также будет много дополнительных действий, таких как сравнение, описанное ранее.
Когда я понял это, я решил провести некоторое тестирование.
Первые результаты показали мне, что str1.intern() == str2.intern()
был быстрее чем str1.equals(str2)
,
Такое поведение было вызвано тем, что String.intern()
метод является родным, поэтому его не следует интерпретировать каждый раз и String.equals()
это метод Java
Итак, я решил использовать -Xcomp
возможность заставить JVM компилировать весь код при запуске.
После этого показал лучшую скорость, чем стажер.
Я проверил это на Java 6 и 7.
Итак, мой вопрос: вы когда-нибудь видели ситуацию, когда интернирование увеличивало скорость сравнения строк? Я да как это может быть?
Или, может быть intern()
может помочь только сэкономить больше свободной памяти?
2 ответа
String.intern()
предназначен для уменьшения использования памяти.
Используйте интернированные строки (если вообще когда-либо), когда у вас много-много копий одной и той же строки в памяти. интернируя строки, все эти копии будут использовать одну и ту же ссылку.
Я видел, что интернирование строк полезно, когда у меня есть миллионы копий одной и той же строки.
Как и в случае любого вида оптимизации, делайте это только после того, как возникнет проблема с производительностью или памятью, и вы профилировали ее, чтобы обнаружить, что это узкое место.
См. Этот пост в блоге для более подробной информации об интернировании строк.
На ваш вопрос о том, почему 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) Сравнение вашей строки с другими в одном ведре - может быть, несколько, но все же должно быть быстрее, чем equals()
4) и 5) быстро
И не забывайте, что вышеупомянутые операции должны быть выполнены только один раз для любой строки, если она intern()
ed результат возвращается из первого сравнения.