Где хранится String Pool (в какой области памяти)?
String Pool — это специальная область, где JVM хранит уникальные строки. Его расположение менялось в разных версиях Java.
🟢 Junior Level
String Pool — это специальная область, где JVM хранит уникальные строки. Его расположение менялось в разных версиях Java.
Краткая история:
- Java 6 и раньше: PermGen (специальная область для метаданных) — часто возникала ошибка
OutOfMemoryError: PermGen space - Java 7+: Java Heap (обычная куча, где живут все объекты) — теперь GC может удалять неиспользуемые строки из пула
Почему это важно: В современной Java String Pool находится в Heap, поэтому он ограничен общим размером памяти (-Xmx), а не отдельным лимитом.
Простая аналогия: PermGen — как маленький сейф с фиксированным размером. Heap — как большой склад, который можно расширить.
Практический смысл: в Java 7+ вы можете интернировать больше строк без отдельной настройки, но теперь пул конкурирует за ту же память, что и ваши объекты.
Когда расположение String Pool не имеет значения
Для 95% приложений это академическое знание. Знание важно при:
(1) массовом intern(), (2) тюнинге GC, (3) миграции между версиями Java.
🟡 Middle Level
Детали по версиям
Java 6: PermGen
- PermGen — отдельная область памяти для метаданных классов
- Размер ограничен (
-XX:MaxPermSize, обычно 64-256MB) - GC в PermGen работал неэффективно
- Чрезмерное
intern()→OOM: PermGen space
Java 7 (точнее, 7u6): String Pool перемещён из PermGen в Java Heap.
- Перемещён в основную кучу
- String Pool делит память со всеми объектами приложения
- GC эффективно удаляет строки без ссылок
- Ограничен только
-Xmx
Java 8+: Metaspace (НЕ String Pool!)
- PermGen заменён на Metaspace (в Native Memory)
- String Pool остался в Java Heap (не в Metaspace!)
- Распространённое заблуждение — думать, что пул переехал в Metaspace
Практическое применение
// В Java 7+ можно смело интернировать больше строк
for (String city : cities) {
city = city.intern(); // Не вызовет OOM: PermGen
}
// Но может вызвать OOM: Java heap space, если куча заполнена
Типичные ошибки
-
Ошибка: Думать, что String Pool в Metaspace Решение: Пул в Heap. Metaspace — только для метаданных классов
-
Ошибка: Не настраивать StringTableSize при массовом intern() Решение:
-XX:StringTableSize=1000003
🔴 Senior Level
Internal Implementation
Структура памяти JVM (Java 8+):
JVM Memory Layout:
├── Heap
│ ├── Young Generation (Eden, S0, S1)
│ ├── Old Generation
│ └── String Pool (StringTable) ← ЗДЕСЬ
├── Metaspace (Native Memory)
│ └── Class metadata, method data
└── Code Cache
└── JIT compiled code
StringTable:
// OpenJDK — StringTable — нативная хеш-таблица в C++
class StringTable : public RehashableHashtable<oop, mtSymbol> {
// oop (ordinary object pointer) — внутренний тип JVM для ссылки на Java-объект.
// mtSymbol — категория памяти в JVM (Symbol = строковые данные).
// Хранится в C++ heap, но сами String объекты — в Java Heap
};
Эволюция — детали переезда
Java 6 (PermGen):
- Строки в пуле жили вечно (или до OOM)
- GC не чистил PermGen эффективно
-XX:MaxPermSize=256m— жёсткий лимит
Java 7 (переезд в Heap):
- JEP: перемещение String Table в Java Heap
- Причина: PermGen удалялся в будущих версиях
- Строки стали обычными объектами для GC
Java 8 (Metaspace):
- PermGen удалён полностью
- Metaspace — Native Memory, авто-расширение
- String Pool не переехал — остался в Heap
Архитектурные Trade-offs
Пул в Heap — плюсы:
- GC управляет строками как обычными объектами
- Нет отдельного лимита — ограничен общим
-Xmx - String entries без ссылок могут быть собраны GC
Пул в Heap — минусы:
- Большое количество интернированных строк конкурирует за Heap с бизнес-объектами
- Может увеличить время GC pause (больше объектов для сканирования)
- G1 GC: StringTable scan добавляет overhead к evacuation pause
Edge Cases
-
GC и String Pool: В Java 7+ строки из пула МОГУТ быть собраны GC, если на них нет strong references. Но если вы храните ссылки — они не собираются.
-
Weak References в StringTable: Некоторые JVM экспериментировали с weak references для записей StringTable, но в HotSpot используются strong references.
-
String Deduplication vs Pool: Дедупликация (G1 GC) объединяет
byte[]массивы в Heap, но это отдельный механизм от String Pool.
Производительность
| Метрика | PermGen (Java 6) | Heap (Java 7+) | | ————— | ————————– | ———————— | | Max size | -XX:MaxPermSize (64-256MB) | -Xmx (GB+) | | GC efficiency | Poor | Good | | String eviction | Manual (restart) | Automatic (GC) | | OOM risk | High (PermGen space) | Medium (Java heap space) |
Production Experience
Сценарий: Миграция приложения с Java 8 на Java 17:
- Команда думала, что String Pool в Metaspace
- Настроили
-XX:MaxMetaspaceSize=512m, но не увеличили-Xmx - Результат:
OOM: Java heap spaceпри нагрузке - Fix: увеличили
-Xmxс 2g до 4g, пул заработал корректно
Monitoring
# Проверить размер StringTable
jcmd <pid> VM.stringtable -verbose
# Memory usage
jstat -gc <pid> 1000
# Heap dump анализ
jmap -dump:live,format=b,file=heap.hprof <pid>
# В MAT: java.lang.String → dominator tree
Best Practices для Highload
- String Pool в Heap → учитывайте его при расчёте
-Xmx - При массовом
intern():-XX:StringTableSize=1000003(или больше) - Мониторьте через
jcmd VM.stringtable - Для автоматической дедупликации:
-XX:+UseStringDeduplication(G1 GC)
🎯 Шпаргалка для интервью
Обязательно знать:
- Java 6 и ниже: String Pool в PermGen (фиксированный размер, частые OOM)
- Java 7+: String Pool перемещён в Java Heap (управляется GC, ограничен
-Xmx) - Java 8+: Metaspace заменил PermGen, но String Pool остался в Heap (НЕ в Metaspace!)
- В Heap GC может удалять строки из пула, если на них нет ссылок
- Распространённое заблуждение — думать, что пул в Metaspace
- StringTable — нативная хеш-таблица в C++, но объекты String — в Java Heap
Частые уточняющие вопросы:
- Почему перенесли String Pool из PermGen в Heap? — PermGen удалялся, GC в PermGen работал неэффективно, в Heap строки стали обычными объектами для GC.
- Может ли String Pool вызвать OOM? — Да,
OOM: Java heap spaceв Java 7+ (раньшеOOM: PermGen space). - В какой области памяти String Pool в Java 17? — В Java Heap. Не в Metaspace, не в Code Cache.
- Как мониторинг String Pool? —
jcmd <pid> VM.stringtable -verbose.
Красные флаги (НЕ говорить):
- ❌ “String Pool в Metaspace” — самая частая ошибка, пул в Heap
- ❌ “String Pool имеет отдельный лимит памяти” — ограничен общим
-Xmx - ❌ “GC не чистит String Pool” — в Java 7+ может удалять unreachable записи
- ❌ “PermGen и Metaspace — одно и то же” — Metaspace в Native Memory, PermGen был в Heap
Связанные темы:
- [[1. Как работает String Pool]]
- [[12. Может ли String Pool вызвать OutOfMemoryError]]
- [[3. Когда стоит использовать intern()]]
- [[22. Что такое String deduplication в G1 GC]]