Введение
Структура данных для повторного использования строк. В информатике интернирование строк — это метод хранения только одной копии каждого уникального строкового значения, которое должно быть неизменным. Интернирование строк повышает эффективность некоторых задач обработки строк по времени или объему памяти, но требует больше времени при создании или интернировании строки. Уникальные значения хранятся в пуле интернированных строк. Единственная копия каждой строки называется её интерном и обычно находится с помощью метода класса строки, например, `String.intern()` в Java. Все строковые константы времени компиляции в Java автоматически интернируются этим методом. Интернирование строк поддерживается некоторыми современными объектно-ориентированными языками программирования, включая Java, Python, PHP (начиная с версии 5.4), Lua и .NET. Lisp, Scheme, Julia, Ruby и Smalltalk — это языки, в которых тип symbol по сути является интернированной строкой. Библиотека Standard ML of New Jersey содержит тип atom, который выполняет ту же функцию. Селекторы Objective-C, которые в основном используются как имена методов, являются интернированными строками. Интернировать можно не только строки, но и другие объекты. Например, в Java, при упаковке примитивных значений в объекты-обёртки, определённые значения (любое boolean, любой byte, любой char от 0 до 127, а также любой short или int в диапазоне от -128 до 127) интернируются, и любые два преобразования одного из этих значений гарантированно приводят к одному и тому же объекту.
In computer science, string interning is a method of storing only one copy of each distinct string value, which must be immutable. Interning strings makes some string processing tasks more time efficient or space efficient at the cost of requiring more time when the string is created or interned. The distinct values are stored in a string intern pool. The single copy of each string is called its intern and is typically looked up by a method of the string class, for example String. intern in Java. All compile time constant strings in Java are automatically interned using this method. String interning is supported by some modern object oriented programming languages, including Java, Python, PHP (since 5.4), Lua
and NET languages. Lisp, Scheme, Julia, Ruby and Smalltalk are among the languages with a symbol type that are basically interned strings. The library of the Standard ML of New Jersey contains an atom type that does the same thing. Objective C's selectors, which are mainly used as method names, are interned strings. Objects other than strings can be interned. For example, in Java, when primitive values are boxed into a wrapper object, certain values (any boolean, any byte, any char from 0 to 127, and any short or int between −128 and 127) are interned, and any two boxing conversions of one of these values are guaranteed to result in the same object.
История
Lisp ввел понятие интернированных строк для своих символов. Исторически структура данных, используемая как пул интернированных строк, называлась oblist (при реализации в виде связанного списка) или obarray (при реализации в виде массива). В современных диалектах Lisp обычно различают символы и строки; интернирование заданной строки возвращает существующий символ или создает новый, имя которого соответствует этой строке. Символы часто обладают дополнительными свойствами, которых нет у строк (например, хранилищем для связанных значений или пространствами имен): это различие также полезно для предотвращения случайного сравнения интернированной строки с строкой, которая не обязательно интернирована, что может приводить к непостоянным ошибкам в зависимости от сценариев использования.
Мотивация
Интернирование строк ускоряет сравнение строк, которое иногда является узким местом в приложениях (таких как компиляторы и среды выполнения динамических языков программирования), интенсивно использующих ассоциативные массивы с ключами-строками для поиска атрибутов и методов объектов. Без интернирования сравнение двух различных строк может потребовать проверки каждого символа обеих строк. Это медленно по нескольким причинам: сложность сравнения составляет O(n), где n – длина строк; обычно требуется чтение данных из нескольких областей памяти, что занимает время; и эти чтения заполняют кэш процессора, уменьшая объем доступной кэш-памяти для других задач. При использовании интернированных строк после первоначальной операции интернирования достаточно простой проверки идентичности объектов, обычно реализуемой как проверка равенства указателей – всего одна машинная инструкция без обращения к памяти. Интернирование строк также снижает потребление памяти, если существует множество экземпляров одной и той же строки, например, при чтении данных из сети или хранилища. Такие строки могут содержать магические числа или информацию о сетевых протоколах. Например, XML-парсеры могут интернировать имена тегов и атрибутов для экономии памяти. При передаче объектов по сети с использованием потоков объектов сериализации Java RMI интернированные строки могут передаваться более эффективно, поскольку при сериализации вместо дубликатов объектов используется дескриптор объекта String.
Многопоточность
Если интернированные строки изменяемы, то одним из недостатков является то, что интернирование строк может быть проблематичным при использовании в многопоточной среде. Во многих системах интерны строк должны быть глобальными для всех потоков в пределах адресного пространства (или для любых контекстов, которые могут обмениваться указателями), следовательно, пулы интернов являются глобальными ресурсами, требующими синхронизации для безопасного одновременного доступа. Хотя это затрагивает только создание строк (где пул интернов необходимо проверять и, при необходимости, изменять), и двойная проверка блокировки может быть использована на платформах, где это безопасная оптимизация, необходимость взаимного исключения при изменении пула интернов может быть дорогостоящей. Вероятность конфликтов также можно снизить, разделив пространство строк на несколько пулов, которые можно синхронизировать независимо друг от друга.
Восстановление неиспользованных интернированных струн
Многие реализации интернированных строк не пытаются освободить (вручную или иным способом) строки, которые больше не используются. Для приложений, где количество интернированных строк невелико или фиксировано, или которые существуют недолго, потеря системных ресурсов может быть допустимой. Однако для долгоживущих систем, в которых во время выполнения создается большое количество интернированных строк, может возникнуть необходимость в освобождении неиспользуемых интернов. Эту задачу может выполнять сборщик мусора, но для его корректной работы в пуле интернов должны храниться слабые ссылки на интернированные строки.