Можно ли удалить строку из пула строк в JVM
Что проверяют
Понимаете ли вы, где физически лежит пул строк и почему вопрос про удаление сводится к достижимости, а не к отдельному методу. Заодно проверяют, не остались ли ваши знания на уровне Java 6.
Как отвечать
Метода вроде unintern нет, вручную выкинуть строку из пула нельзя. Но собрать её сборщиком мусора можно, и это главное в ответе.
Пул это не отдельное хранилище объектов, а нативная хеш-таблица StringTable со ссылками на строки в куче. С Java 7 сами строки лежат в обычной куче, поэтому недостижимая строка собирается как любой другой объект, а запись в таблице вычищается вместе с ней.
Разница между двумя способами попасть в пул важна:
- строковый литерал приходит из константного пула класса и достижим, пока жив класс и его загрузчик. Он переживёт всё приложение, если загрузчик не выгружается;
- строка, добавленная вызовом
intern()в рантайме, живёт ровно до тех пор, пока на неё есть ссылка снаружи.
Полезно упомянуть настройки: -XX:StringTableSize задаёт число корзин таблицы, -XX:+PrintStringTableStatistics печатает её состояние при выходе.
Где спотыкаются
Говорят, что пул лежит в PermGen и переполняет его. С Java 7 он в куче, а самого PermGen нет с Java 8, его место занял Metaspace. Ответ про PermGen сразу датирует знания.
Выводят невозможность удаления из неизменяемости строк. Связи нет: иммутабельность объясняет, почему одну строку безопасно делить между владельцами, но о сборке мусора не говорит ничего.
Зовут intern() на потоке пользовательских данных ради экономии памяти. Вызов дороже обычного создания строки и удерживает значения в таблице. Для схлопывания одинаковых строк есть -XX:+UseStringDeduplication, это работа сборщика, а не прикладного кода.