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

В какой области памяти хранятся статические поля

2.3 Middle🔥 201 комментариев
#JVM и управление памятью#Основы Java

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

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

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

# В какой области памяти хранятся статические поля

Статические поля в Java хранятся в MethodArea/Metaspace (в Java 8+) или PermGen (в Java 7 и раньше). Это область памяти, которая содержит информацию о классе и постоянно существует во время выполнения программы.

Структура памяти в Java

┌─────────────────────────────┐
│       Heap (Куча)           │  ← Объекты экземпляров
│  (Управляется GC)           │
└─────────────────────────────┘

┌─────────────────────────────┐
│    Stack (Стек)             │  ← Локальные переменные, ссылки
│  (По одному для потока)      │
└─────────────────────────────┘

┌─────────────────────────────┐
│  MethodArea/Metaspace       │  ← Статические поля, методы, классы
│  (Общая для всех потоков)   │
└─────────────────────────────┘

MethodArea в Java 8+

В Java 8 введена Metaspace — замена PermGen. Она находится в Off-Heap памяти (система, а не JVM).

public class Configuration {
    // Статическое поле — хранится в Metaspace
    public static final String APP_NAME = "MyApp";
    public static final int MAX_USERS = 1000;
    
    // Обычное поле — хранится в Heap
    private String userName;
    
    public static void main(String[] args) {
        // Локальная переменная — хранится в Stack
        int count = 0;
        
        // Объект — хранится в Heap
        Configuration config = new Configuration();
    }
}

Визуализация хранения данных

MethodArea/Metaspace:
├── Класс Configuration
│   ├── METHOD appName = "MyApp" (статическое поле)
│   ├── METHOD MAX_USERS = 1000 (статическое поле)
│   ├── METHOD main() (метод)
│   └── METHOD ...
└── Класс OtherClass
    └── ...

Heap:
├── Configuration instance #1
│   └── userName = "John" (экземплярное поле)
└── Configuration instance #2
    └── userName = "Jane" (экземплярное поле)

Stack (Поток 1):
├── count = 0 (локальная переменная)
├── config = ссылка на объект в Heap
└── ...

Stack (Поток 2):
├── count = 5 (локальная переменная)
├── config = ссылка на объект в Heap
└── ...

Практический пример

public class MemoryAreas {
    
    // СТАТИЧЕСКОЕ ПОЛЕ — Metaspace
    private static String appName = "MyApplication";
    
    // СТАТИЧЕСКОЕ ПОЛЕ — Metaspace
    private static List<User> cache = new ArrayList<>();
    
    // ЭКЗЕМПЛЯРНОЕ ПОЛЕ — Heap (в каждом объекте)
    private String userName;
    
    public static void main(String[] args) {
        // ЛОКАЛЬНАЯ ПЕРЕМЕННАЯ — Stack
        int count = 0;
        
        // ОБЪЕКТ — Heap
        MemoryAreas obj = new MemoryAreas();
        
        // Доступ к статическому полю (Metaspace)
        System.out.println(MemoryAreas.appName);
        
        // Доступ к экземплярному полю (Heap)
        obj.userName = "Alice";
    }
}

Время жизни статических полей

public class Lifecycle {
    public static int counter = 0;
    
    public static void main(String[] args) {
        // 1. Класс загружается в Metaspace при первом использовании
        System.out.println(Lifecycle.counter); // 0
        
        // 2. Статическое поле инициализируется один раз
        Lifecycle.counter = 5;
        
        // 3. Значение сохраняется в Metaspace до конца программы
        System.out.println(Lifecycle.counter); // 5
        
        // 4. Все потоки видят одно и то же значение
        new Thread(() -> System.out.println(Lifecycle.counter)).start(); // 5
        
        // 5. После завершения программы — освобождается вместе с Metaspace
    }
}

Различия между типами данных

public class DataStorage {
    
    // 1. СТАТИЧЕСКОЕ ПОЛЕ (Metaspace)
    public static String appName = "MyApp";
    
    // 2. СТАТИЧЕСКАЯ ПЕРЕМЕННАЯ В МЕТОДЕ (Stack при вызове)
    public static void printName() {
        String localName = appName; // Stack
        System.out.println(localName);
    }
    
    // 3. ЭКЗЕМПЛЯРНОЕ ПОЛЕ (Heap)
    private int userId;
    
    // 4. ЭКЗЕМПЛЯРНАЯ ПЕРЕМЕННАЯ (Stack при вызове)
    public void setUser(String name) {
        String localUserName = name; // Stack
        // Используется...
    } // localUserName удаляется из Stack
}

// Тестирование:
public static void main(String[] args) {
    // appName находится в Metaspace и существует постоянно
    // obj находится в Heap
    // id находится в Stack этого потока
    
    DataStorage obj = new DataStorage();
    int id = 1;
    obj.setUser("Alice");
}

PermGen vs Metaspace

Java 7 и раньше (PermGen)

Heap:
├── Объекты приложения
└── ...

PermGen (часть Heap):
├── Классы
├── Методы
├── Статические поля
└── String Pool

Проблема: PermGen имела фиксированный размер → OutOfMemoryError

Java 8+ (Metaspace)

Heap:
├── Объекты приложения
└── ...

Metaspace (Native Memory):
├── Классы
├── Методы
├── Статические поля
└── String Pool

Преимущество: Metaspace использует системную память → без ограничений

Конфигурация памяти

# Для Java 7 и раньше (PermGen)
java -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m MyApp

# Для Java 8+ (Metaspace)
java -Xms1024m -Xmx1024m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m MyApp

Где хранится что

public class StorageExample {
    
    public static void main(String[] args) {
        
        // 1. Статический текст (не массив)
        String staticText = "Hello";
        // Содержимое "Hello" может быть в String Pool
        // (часть Metaspace или Heap в зависимости от версии)
        
        // 2. Статический массив объектов
        static Integer[] staticArray = {1, 2, 3};
        // Сам массив (structure) — в Metaspace
        // Объекты Integer — в Heap
        // Ссылка staticArray — в Metaspace
        
        // 3. Статическая коллекция
        static List<User> users = new ArrayList<>();
        // Ссылка на List — в Metaspace
        // Сам ArrayList объект — в Heap
        // Элементы List — в Heap
    }
}

Одна копия для всех потоков

public class SharedStatic {
    private static int counter = 0;
    
    public static void main(String[] args) {
        // Все потоки видят ОДНО и то же значение в Metaspace
        
        Thread t1 = new Thread(() -> {
            counter++;
            System.out.println("T1: " + counter);
        });
        
        Thread t2 = new Thread(() -> {
            counter++;
            System.out.println("T2: " + counter);
        });
        
        t1.start();
        t2.start();
        
        // Race condition! Нужна синхронизация
    }
}

Итоговая таблица

Тип данныхОбласть памятиВремя жизниКоличествоВидимость
Статическое полеMetaspaceДо конца программы1 на классВсе потоки
Экземплярное полеHeapДо удаления объекта GCПо числу объектовОдин объект
Локальная переменнаяStackДо конца методаПо числу вызововОдин поток
Параметр методаStackДо конца методаПо числу вызововОдин поток

Ключевые моменты

  1. Статические поля — Metaspace (Java 8+) или PermGen (Java 7-)
  2. Metaspace находится в Off-Heap памяти (системная память)
  3. Одна копия статического поля для всего приложения
  4. Все потоки видят одно значение статического поля
  5. Метаданные классов также в Metaspace (методы, поля, классы)
  6. Статические поля инициализируются один раз при загрузке класса
  7. Память освобождается в конце программы