openjdk.ruOpenJDK на русском

JEP draft: Deprecate the UTF-16-only String Representation

Объявление устаревшим представления строк только в UTF-16

ОтветственныйStuart Marks
ТипFeature
ОбластьJDK
СтатусDraft
Компонентcore-libs / java.lang
Создан2025/11/05 23:10
Обновлён2025/11/12 19:22
Задача8371379

Аннотация

Объявить устаревшей, с последующим удалением, возможность отключать Compact Strings. Compact Strings появились в JDK 9 для экономии памяти и включены по умолчанию. В будущем альтернатива Compact Strings — представление строк только в UTF-16 — будет удалена.

Мотивация

В JDK 1.0 у объектов String было единственное внутреннее представление: массив значений char. Каждое значение char занимало два байта (16 бит), а строковые данные, хранившиеся в массиве char, были закодированы в UTF-16. Даже если строковые данные можно было закодировать одним байтом, они кодировались в UTF-16 и занимали два байта на символ. Такой режим работы называется режимом «только UTF-16».

Появление Compact Strings в JDK 9 изменило внутреннее представление объектов String. (Изменение касалось исключительно реализации; публичный API не менялся.) Новое внутреннее представление допускало две формы: один байт на символ (символы в кодировке ISO Latin 1) или два байта на символ (в кодировке UTF-16). Многие строки можно закодировать в ISO Latin 1, используя лишь один байт на символ и существенно экономя место по сравнению с режимом «только UTF-16», поэтому Compact Strings были включены по умолчанию.

Соответственно, в JDK 9 и более поздних выпусках возможны три внутренних представления String и три пути выполнения кода для каждой операции String:

  1. представление Compact Strings в кодировке ISO Latin 1;
  2. представление Compact Strings в кодировке UTF-16; и
  3. представление «только UTF-16».

Сопровождение трёх путей выполнения кода — это дополнительная нагрузка. Поскольку Compact Strings включены по умолчанию, к их путям выполнения кода было применено множество оптимизаций, и они тщательно протестированы. Пути выполнения кода для режима «только UTF-16», напротив, оптимизировались меньше и протестированы не так тщательно, как пути Compact Strings. Более того, ряд ошибок возникал только в режиме «только UTF-16».

Удаление представления «только UTF-16» и поддерживающего его кода упростит реализацию String и снизит затраты на сопровождение JDK.

Описание

Мы предлагаем объявить режим «только UTF-16» устаревшим с последующим удалением в одном из будущих выпусков. Когда в будущем этот режим будет удалён, изменится только внутреннее представление String; никакие публичные API не изменятся, и это никак не повлияет на совместимость существующего исходного кода или двоичных файлов.

Объявление режима «только UTF-16» устаревшим затрагивает только пользователей -XX:-CompactStrings. Этот параметр командной строки появился в JDK 9, чтобы отключать Compact Strings и запускать систему в режиме «только UTF-16», прежде всего на случай, если характер нагрузки и состав данных приложения приводили к снижению производительности при включённых Compact Strings. В JDK NN он продолжит работать так же, как в JDK 9, но будет выдавать предупреждение о том, что возможность работы в режиме «только UTF-16» в будущем будет удалена.

Разработчикам приложений следует проверить свои скрипты и конфигурации запуска Java, чтобы определить, используется ли в каком-либо из них параметр -XX:-CompactStrings. Если этот параметр используется, разработчикам следует удалить его (или, что равнозначно, заменить на -XX:+CompactStrings) и протестировать систему, чтобы оценить возможные последствия работы с включёнными Compact Strings.

Риски

В отличие от других портов JDK, порт ARM32 использует режим «только UTF-16». Порт ARM32 не тестировался в режиме Compact Strings. Поэтому, вероятно, порт ARM32 потребует доработки, чтобы довести его реализацию Compact Strings до качества, пригодного для промышленной эксплуатации. Как вариант, поддержку ARM32 можно полностью исключить из JDK.

В азиатских языках, таких как китайский, японский и корейский (CJK), используется множество символов, которые невозможно закодировать одним байтом. Режим «только UTF-16» достаточно хорошо подходит для строковых данных на этих языках. При включённых Compact Strings система должна выполнять дополнительную работу: проверять каждую строку, можно ли закодировать её в ISO Latin 1; если нельзя, строковые данные будут закодированы и сохранены в UTF-16. Поэтому приложение, которое обрабатывает текст CJK и работает с включёнными Compact Strings, может тратить дополнительное процессорное время на проверку возможности закодировать строковые данные в ISO Latin 1 лишь для того, чтобы выяснить, что их всё равно нужно кодировать в UTF-16. Это может привести к росту потребляемого процессорного времени без какой-либо итоговой экономии памяти.

Ключевое проектное допущение, лежащее в основе Compact Strings, состоит в том, что даже в приложениях, которые обрабатывают в основном строковые данные CJK, будет много других строк (например, имён классов, заголовков запросов, URL и т. д.), которые можно закодировать в ISO Latin 1, и это приведёт к итоговой экономии памяти и снижению накладных расходов на сборку мусора. Однако могут существовать приложения, для которых это допущение неверно. Эксплуатирующие организации могут предпочесть запускать такие приложения в промышленной среде с отключёнными Compact Strings. С момента появления реализация Compact Strings была оптимизирована, поэтому такое снижение производительности, возможно, уже удалось смягчить. Однако, когда режим «только UTF-16» в конечном итоге будет удалён, таким приложениям придётся перейти на Compact Strings, возможно, со снижением производительности, либо они смогут бессрочно оставаться на более старых выпусках JDK.

В режиме «только UTF-16» функция JNI GetStringCritical возвращает прямой указатель на внутренний массив char объекта String. С Compact Strings эта функция создаёт копию массива. У приложений, которые активно используют GetStringCritical, при переходе с режима «только UTF-16» на Compact Strings снизится производительность. Очевидного способа смягчить эту проблему нет.