2010-08-18 3 views
24

Я видел много примитивных примеров, описывающих, как работает String intern(), но мне еще предстоит увидеть реальный случай использования, который выиграет от него.Реальная жизнь, практический пример использования String.intern() в Java?

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

Может ли кто-нибудь предоставить пример использования intern() в производственной среде с большим успехом? Может быть, это пример популярного предложения с открытым исходным кодом?

Edit: я имею в виду ручной интернатуру, а не гарантированному интернирование строковых литералов и т.д.

ответ

1

Не полный ответ, но дополнительная пища для размышлений (found here):

Таким образом, первичный преимущество в этом случае состоит в том, что использование оператора == для интернализованных строк намного быстрее, чем использование метода equals() [для неинтерминированных строк]. Итак, используйте метод intern(), если вы собираетесь сравнивать строки больше, чем время или три.

+0

Это правда, но существует множество исключений из этого обобщения: - Если вероятность того, что ваши строки имеют одинаковую длину, очень минимальна, а количество строк, которые вы, возможно, будете intern(), высок , можно утверждать, что, поскольку equals() выполняет сначала проверку размера, вы необоснованно подвергаете себя исключениям OGG PermGen. –

+0

Вы правы, но по производительности у вас есть O (n) для равных и O (1) для '=='. Я согласен, что худший случай возникает только в том случае, если обе строки имеют одинаковый размер и отличаются только на последнем символе. Обычно это довольно редкий случай. –

+2

Ответ неверен. Первое, что делает String.equals, - это проверка равенства ссылок, прежде чем проверять семантическое равенство. Таким образом, для двух интернализированных строк == и .equals, ну, равно .... – PaulJWilliams

1

У нас была производственная система, которая обрабатывает буквально миллионы частей данных за раз, многие из которых имеют строковые поля. Мы должны интернировали строки, но была ошибка, которая означала, что мы не были. Исправляя ошибку, мы избегали делать очень дорогостоящие (не менее 6 цифр, возможно, 7) обновление сервера.

+1

Можете ли вы уточнить? , например. Какие данные? Был ли он управляемым пользователем или внутренним/cron? Что делается с данными? и т. д. При таком уровне детализации пример будет более понятным. Благодаря! –

+1

Im ограничено тем, что я могу раскрыть, но в основном это была обработка финансовых транзакций. Мы читаем весь объем данных из массивной базы данных и выполняем на нем большие операции типа хранилища даты и хранилища, чтобы различать агрегированные аспекты. Некоторые текстовые поля в данных не были интернированы при чтении из БД, что привело к массовому раздуванию памяти и большому сокращению нашей вычислительной мощности. – PaulJWilliams

0

Никогда, никогда, используйте intern из предоставленных пользователем данных, так как это может привести к атак типа «отказ в обслуживании» (поскольку строки intern() ed никогда не освобождаются). Вы можете выполнить валидацию по введенным пользователем строкам, но затем вы выполнили большую часть работы, необходимой для intern().

+0

Ваша точка в intern() 'ed Строки, которые не освобождаются, неверны (в зависимости от JVM). Наиболее релевантные JVM используют слабые ссылки для обеспечения gc. –

21

интернирование может быть очень полезным, если у вас есть N строки, которые могут принимать только K различные значения, где N намного превышает K. Теперь, вместо сохранения в памяти N строк, вы будете хранить только до K.

Например, у вас может быть тип ID, который состоит из 5 цифр. Таким образом, могут быть только значения 10^5. Предположим, вы теперь разбираете большой документ, который имеет много ссылок/перекрестных ссылок на значения ID. Предположим, что этот документ содержит 10^9 ссылок на итоговые данные (очевидно, некоторые ссылки повторяются в других частях документов).

So N = 10^9 и K = 10^5 в этом случае. Если вы не интернируете строки, вы будете хранить строки 10^9 в памяти, где много этих строк: equals (по Pigeonhole Principle). Если вы используете intern() строку ID, которую вы получаете, когда вы разбираете документ, и вы не держите ссылки на строки, которые вы читаете из документа (чтобы они могли собирать мусор), вам больше не понадобится хранить больше чем 10^5 строки в памяти.

+2

Я считаю, что это почти идеальная оценка, спасибо за абстрагирование ее от полигенных смазок.Моя трудность придумывать осязаемый пример заключается в том, что даже в вышеприведенном случае чаще всего вы можете передавать входные данные и работать над ним в кусках по сравнению со всеми сразу. Потоковая передача и интерн() (если применимо) почти всегда предпочтительнее, если предположить, что в случае удаленного источника незначительная сетевая латентность/воздействие. Дело в том, что я никогда не видел прецедента, который соответствует порогу строк, необходимых для рассмотрения intern(), но не может быть потоковым, разделенным и завоеванным. –

+1

@Tom: см. Также http://www.stackoverflow.com/questions/1356341/will-interning-strings-help-performance-in-a-parser - это также связанный с парсером и мотивированный тем же принципом Pigeonhole. XML-документ может содержать один миллион элементов '', но, вероятно, только очень мало типов элементов. Вы можете ставить имена элементов таким образом, чтобы '' item "' отображался только один раз в памяти (не считая временные экземпляры мусора, которые сразу же отдают предпочтение его представителю 'intern()'). – polygenelubricants

+0

важно добавить, что с Java 7 on интернированные строки больше не живут в пространстве перментонов, поэтому они могут быть собраны в мусор, как и любой другой объект. (источник: http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html) –

1

Примеров, где интернирование будет полезно включать большие числа строк, где:

  • строки, вероятно, чтобы выжить несколько циклов GC, и
  • там, вероятно, будут несколько копиями большого процента Строки.

Типичные примеры включают разделение/разбор текста на символы (слова, идентификаторы, URI), а затем прикрепление этих символов к долговечным структурам данных. Обработка XML, компиляция языка программирования и тройные магазины RDF/OWL оживают в качестве приложений, где интернирование, вероятно, будет полезным.

Но интернирование не без проблем, особенно если выяснится, что предположения выше не являются правильными:

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

Наконец, интернируя потенциально увеличивает GC накладные расходы за счет увеличения количества объектов, которые должны быть прослежены и скопированы, и за счет увеличения числа слабых ссылок, которые должны быть рассмотрены. Это увеличение накладных расходов должно быть сбалансировано с уменьшением накладных расходов GC, которые являются результатом эффективного интернирования.