Java 8 String дедупликация против String.intern()
Я читаю о функции в Java 8 обновление 20 для дедупликации строк ( дополнительная информация), но я не уверен, что это в основном делает String.intern()
устарели.
Я знаю, что эта функция JVM нуждается в сборщике мусора G1, который не может быть вариантом для многих, но если предположить, что кто-то использует G1GC, есть ли разница / преимущество / недостаток автоматической дедупликации, выполняемой JVM по сравнению с необходимостью вручную intern
ваши строки (одно очевидное преимущество заключается в том, что вам не нужно загрязнять ваш код вызовами intern()
)?
Это особенно интересно, учитывая, что Oracle может сделать G1GC GC по умолчанию в Java 9
3 ответа
С помощью этой функции, если у вас есть 1000 различных объектов String, все с одинаковым содержимым "abc"
, JVM может заставить их делить то же самое char[]
внутренне. Тем не менее, у вас все еще есть 1000 различных String
объекты.
С intern()
, у вас будет только один String
объект. Так что, если вы заботитесь о сохранении памяти, intern()
было бы лучше. Это сэкономит место, а также время GC.
Тем не менее, производительность intern()
не так здорово, в прошлый раз я слышал. Возможно, вам лучше иметь собственный строковый кеш, даже используя ConcurrentHashMap
... но вы должны проверить это, чтобы убедиться.
В качестве комментария ссылки смотрите: 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 на C++. String.intern()
даже после настройки параметров jvm. (И бонус: вам не нужно настраивать параметры JVM для масштабирования на другой вход.)
Я хочу представить еще один фактор принятия решений в отношении целевой аудитории:
- Для системного интегратора, имеющего систему, состоящую из множества различных библиотек / структур, с низкой способностью влиять на внутреннюю разработку этих библиотек, StringDeDuplication может быть быстрым победителем, если проблема с памятью. Это повлияет на все строки в JVM, но G1 будет использовать только свободное время для этого. Вы можете даже настроить, когда дедупликация рассчитывается с использованием другого параметра (StringDeduplicationAgeThreshold)
- Для разработчика, создающего свой собственный код, String.intern может быть более интересным. Необходимо тщательно продумать модель предметной области, чтобы решить, стоит ли вызывать стажера и когда. В качестве практического правила вы можете использовать intern, если вы знаете, что строка будет содержать ограниченный набор значений, например, тип перечислимого набора (например, название страны, месяц, день недели...).