Подтвердить что ты не робот

Ядровая дедупликация строк 8 и String.intern()

Я читаю о функции в Java 8 update 20 для дедупликации строк (подробнее), но я не уверен, что это в основном делает String.intern() устарели.

Я знаю, что этой функции JVM нужен сборщик мусора G1, который не может быть вариантом для многих, но при условии, что один использует G1GC, есть ли разница/преимущество/недостаток автоматической дедупликации, выполняемой JVM vs вручную, чтобы intern ваши строки (одним очевидным является то, что вам не нужно загрязнять ваш код вызовами intern())?

Это особенно интересно, учитывая, что Oracle может сделать G1GC GC по умолчанию в java 9

4b9b3361

Ответ 1

С помощью этой функции, если у вас есть 1000 различных объектов String, все с тем же содержимым "abc", JVM может заставить их совместно использовать один и тот же char[] внутри. Однако у вас все еще есть 1000 различных объектов String.

С intern() у вас будет только один объект String. Поэтому, если сохранение памяти будет вашей проблемой, intern() будет лучше. Это сэкономит место, а также время GC.

Однако производительность intern() не такая уж большая, в прошлый раз я слышал. Вам может быть лучше, если у вас есть собственный кеш строки, даже используя ConcurrentHashMap... но вам нужно проверить его, чтобы убедиться.

Ответ 2

В качестве ссылок на комментарии см. http://java-performance.info/string-intern-in-java-6-7-8/. Это очень проницательная ссылка, и я многому научился, однако я не уверен, что ее выводы обязательно "один размер подходит всем". Каждый аспект зависит от потребностей вашего собственного приложения - рекомендуется проводить измерения реальных входных данных!

Основной фактор, вероятно, зависит от того, что вы контролируете:

  • Есть ли у вас полный контроль над выбором GC? Например, в приложении с графическим интерфейсом все еще существует серьезный аргумент в пользу использования Serial GC. (гораздо меньший объем памяти для процесса - думаю, 400 МБ против ~ 1 ГБ для умеренно сложного приложения и гораздо более желательная релиз-память, например, после кратковременного всплеска в использовании). Таким образом, вы можете выбрать это или дать своим пользователям возможность. (Если куча остается небольшой, паузы не должны быть большими). ​​

  • Есть ли у вас полный контроль над кодом? Опция G1GC отлично подходит для сторонних библиотек (и приложений!), Которые вы не можете редактировать.

Второе соображение (в соответствии с ответом @ZhongYu) заключается в том, что String.intern может дедуплицировать объекты String, тогда как G1GC обязательно может только дедуплицировать свое частное поле char[].

Третье соображение может быть связано с использованием ЦП, скажем, если влияние на срок службы аккумулятора ноутбука может быть опасным для ваших пользователей. G1GC запускает дополнительный поток, предназначенный для удаления дубликатов кучи. Например, я играл с этим, чтобы запустить Eclipse, и обнаружил, что он начал начальный период увеличения активности процессора после запуска (думаю, 1 - 2 минуты), но он поселился на небольшой куче "в использовании" и не стал очевидным (просто глаз- свертывание диспетчера задач) Накладные расходы процессора или замедление после этого. Таким образом, я предполагаю, что определенный процент от ядра процессора будет рассмотрен при дедупликации (в течение? После?) Периодов высокой памяти-оттока. (Конечно, могут быть сопоставимые накладные расходы, если вы вызываете String.intern всюду, что также будет работать в серийном, но затем...)

Вам, вероятно, не требуется удаление строк во всех случаях. Вероятно, есть только определенные области кода, которые:

  • действительно влияет на долгосрочное использование кучи, и
  • создать большую долю повторяющихся строк

Используя String.intern выборочно, другие части кода (которые могут создавать временные или полувременные строки) не платят цену.

И, наконец, быстрый плагин для утилиты Guava: Interner, который:

Обеспечивает эквивалентное поведение String.intern() для других неизменяемых типов

Вы также можете использовать это для строк. Возможно, память (и должна быть) связана с вашей максимальной производительностью, поэтому это, вероятно, часто не применяется: однако, когда вам нужно сжимать каждую капли скорости из какой-либо области с горячей точкой, мой опыт в том, что слабая ссылка на Java Решения HashMap работают немного, но последовательно быстрее, чем реализация JVM С++ String.intern(), даже после настройки параметров jvm. (И бонус: вам не нужно настраивать параметры JVM для масштабирования на разные входные данные.)

Ответ 3

Я хочу представить еще один фактор принятия решения относительно целевой аудитории:

  • Для системного интегратора, имеющего систему, состоящую из множества разных библиотек/фреймворков, с низкой способностью влиять на внутреннюю разработку этих библиотек, StringDeDuplication может быть быстрым победителем, если память является проблемой. Это повлияет на все строки в JVM, но G1 будет использовать только свободное время для этого. Вы можете даже настроить настройки DeDuplication, используя другой параметр (StringDeduplicationAgeThreshold)
  • Для разработчиков, профилирующих свой собственный код, String.intern может быть интереснее. Хотевший обзор модели домена необходим, чтобы решить, следует ли звонить стажером и когда. Как правило, вы можете использовать intern, когда знаете, что String будет содержать ограниченный набор значений, например, определенный список (например, название страны, месяц, день недели...).