← Назад к вопросам

Где располагается память выделенная под String Pool?

2.0 Middle🔥 121 комментариев
#JVM и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Где располагается память выделенная под String Pool?

String Pool — это специальная область памяти в Java, которая хранит строковые литералы и обеспечивает оптимизацию памяти. Понимание его локализации критично для оптимизации приложений.

Локализация String Pool в памяти

Java 7 и позже: Heap память

В современной Java (7+) String Pool расположен в HEAP, в выделенной области памяти.

┌─────────────────────────────────────┐
│         HEAP MEMORY                 │
├─────────────────────────────────────┤
│                                     │
│  ┌─────────────────────────────┐   │
│  │   String Pool (Heap)        │   │
│  │  "hello" → [h][e][l][l][o] │   │
│  │  "world" → [w][o][r][l][d] │   │
│  │  "java"  → [j][a][v][a]    │   │
│  └─────────────────────────────┘   │
│                                     │
│  ┌─────────────────────────────┐   │
│  │   Обычные объекты           │   │
│  │   ArrayList, Custom objects  │   │
│  └─────────────────────────────┘   │
│                                     │
└─────────────────────────────────────┘

До Java 7: PermGen (Permanent Generation)

В Java 6 и раньше String Pool был в PermGen — отдельной области памяти, которая не входила в Heap:

┌──────────────────────────────────────┐
│        HEAP (Young + Old Gen)        │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│    PermGen (не переносится при GC)   │
│  ┌──────────────────────────────┐   │
│  │   String Pool                │   │
│  │   Metadata                   │   │
│  │   Bytecode                   │   │
│  └──────────────────────────────┘   │
└──────────────────────────────────────┘

Почему это важно

Сборка мусора (Garbage Collection)

Java 6 и раньше:

  • String Pool не подвергался сборке мусора обычной сборкой Heap
  • При переполнении PermGen возникала ошибка: OutOfMemoryError: PermGen space

Java 7+:

  • String Pool участвует в обычной сборке мусора
  • Неиспользуемые строки из пула удаляются автоматически
  • Уменьшился риск OutOfMemoryError для строк

Пример проблемы в Java 6

// Java 6 - опасный код
for (int i = 0; i < 1000000; i++) {
    String s = new String("prefix_" + i).intern();
    // Каждая интернированная строка попадает в PermGen
    // PermGen переполнится → OutOfMemoryError
}

Java 7+ - безопаснее:

// Java 7+ - GC может очистить String Pool
for (int i = 0; i < 1000000; i++) {
    String s = new String("prefix_" + i).intern();
    // GC может удалить неиспользуемые строки из пула
}

Метаспейс (Java 8+): замена PermGen

Начиная с Java 8, PermGen полностью заменен на Metaspace:

┌────────────────────────────────────┐
│      HEAP (Young + Old Gen)        │
│  ┌──────────────────────────────┐  │
│  │  String Pool (в Heap)        │  │
│  │  "hello", "world", "java"   │  │
│  └──────────────────────────────┘  │
└────────────────────────────────────┘
┌────────────────────────────────────┐
│   NATIVE MEMORY (off-heap)         │
│  ┌──────────────────────────────┐  │
│  │  Metaspace (не Heap!)        │  │
│  │  - Class metadata            │  │
│  │  - Bytecode                  │  │
│  │  - Method metadata           │  │
│  └──────────────────────────────┘  │
└────────────────────────────────────┘

Ключевые отличия Metaspace:

  • Находится в native memory (вне Heap)
  • Растет динамически по мере необходимости
  • Управляется операционной системой
  • Снизилось количество OutOfMemoryError для метаданных

Механизм String Pool

Как строки попадают в пул

1. Строковые литералы (автоматически):

String s1 = "hello";  // Автоматически попадает в String Pool
String s2 = "hello";  // Ссылается на то же место в пуле

System.out.println(s1 == s2);  // true (одна и та же ссылка)

2. Метод intern() (явно):

String s1 = new String("hello");     // Создается в Heap, вне пула
String s2 = s1.intern();             // Добавляется в пул
String s3 = "hello";                 // Уже в пуле

System.out.println(s2 == s3);       // true (обе из пула)
System.out.println(s1 == s2);       // false (разные объекты)

3. Конкатенация на этапе компиляции:

String s1 = "hello" + " " + "world";  // Компилируется в "hello world"
// Эта строка попадает в пул

String s2 = "hello world";
System.out.println(s1 == s2);  // true

Конкатенация на этапе выполнения

String greeting = "hello";
String name = "world";
String result = greeting + " " + name;  // Не автоматически в пуле

// До Java 9: используется StringBuffer
// Java 9+: используется StringBuilder

// Объект result находится в обычной Heap, не в пуле
String fromPool = "hello world";
System.out.println(result == fromPool);  // false

Внутренняя структура String Pool

String Pool реализован как **HashTable**:

// Внутренняя реализация (упрощённо)
private static final StringTable intern = new StringTable();

public String intern() {
    if (this table is in StringTable) {
        return existing string from table;
    } else {
        add this string to table;
        return this;
    }
}

Характеристики:

  • Быстрый поиск: O(1) в среднем
  • Потокобезопасность: использует внутреннюю синхронизацию
  • Размер: не ограничен, но управляется параметрами JVM

Конфигурация String Pool

JVM параметры

StringTableSize:

java -XX:StringTableSize=100000 MyApp
  • По умолчанию: 60013 (Java 8+)
  • Увеличение размера улучшает производительность для больших приложений

Пример перед Java 8:

java -XX:PermSize=128m -XX:MaxPermSize=512m MyApp

Практические рекомендации

1. Избегай избыточного intern():

// ❌ Плохо - создает много объектов в пуле
for (int i = 0; i < 1000000; i++) {
    String s = ("prefix_" + i).intern();
}

// ✅ Хорошо - используй пул только когда нужно
String frequently_used = "common_value".intern();

2. Используй String пул для известных значений:

// ✅ Хорошо
String status = "ACTIVE";        // В пуле
String role = "ADMIN";           // В пуле
String config = "PRODUCTION";    // В пуле

3. Мониторинг String Pool:

jconsole  # Визуальный инструмент для мониторинга Heap
jstat     # Инструмент командной строки
jmap      # Для дампа Heap и анализа

Сравнение версий Java

ВерсияString PoolМестоположениеGCПроблемы
Java 6ДаPermGenНе собираетсяOutOfMemoryError: PermGen
Java 7ДаHeapСобираетсяМеньше ошибок
Java 8+ДаHeapСобираетсяMetaspace вместо PermGen
Java 11+ДаHeapСобираетсяОпция ZGC для низких пауз

Заключение

  • Java 7+: String Pool находится в HEAP, подвергается сборке мусора
  • Java 8+: Метаспейс находится в NATIVE MEMORY (не Heap)
  • String Pool оптимизирует память для строковых литералов
  • Избыточное использование intern() может привести к проблемам с памятью
  • Современная Java (8+) более безопасна для работы со String Pool благодаря Metaspace
Где располагается память выделенная под String Pool? | PrepBro