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

Где хранится примитивное поле класса?

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

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

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

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

Где хранится примитивное поле класса?

Это важный вопрос о структуре памяти JVM. Ответ зависит от того, о каком поле идёт речь: статическом или экземплярном.

Экземплярные примитивные поля (Instance fields)

Ответ: В КУЧЕ, внутри объекта, где этот объект расположен.

public class Person {
    // Экземплярные поля (не static)
    private int age;          // примитив
    private double salary;    // примитив
    private String name;      // ссылка
}

// Использование
Person person = new Person();
// В памяти выглядит так:
//
// СТЕК:
// [person] -> адрес 0x1000
//
// КУЧА (0x1000):
// [Person объект {
//   age: 30          <- примитив ВНУТРИ объекта
//   salary: 50000.0  <- примитив ВНУТРИ объекта
//   name: 0x2000     <- ссылка на String в куче
// }]
//
// КУЧА (0x2000):
// [String: "John"]

Визуально:

СТЕК:
┌─────────────────────┐
│ person: 0x1000      │
└─────────────────────┘
        |
        v
КУЧА:
┌─────────────────────────────────┐
│ Person объект (на 0x1000):      │
│  age: 30                        │ <- примитив в куче
│  salary: 50000.0                │ <- примитив в куче
│  name: 0x2000 ──────┐           │ <- ссылка в куче
└─────────────────────┼───────────┘
                      |
                      v
                ┌──────────────────┐
                │ String "John"    │
                │ (на 0x2000)      │
                └──────────────────┘

Статические примитивные поля (Static fields)

Ответ: В METASPACE (или PermGen в Java 7 и ранее), а НЕ в стеке и НЕ в обычной куче.

public class GlobalCounter {
    // Статическое примитивное поле
    static int totalInstances = 0;  // Хранится в Metaspace
    static double globalRate = 1.5; // Хранится в Metaspace
    
    // Экземплярное примитивное поле
    private int instanceCount;      // Хранится в куче (внутри объекта)
}

// Использование
GlobalCounter counter1 = new GlobalCounter();
GlobalCounter counter2 = new GlobalCounter();

// В памяти:
// METASPACE:
// [GlobalCounter класс {
//   totalInstances: 0       <- статическое поле
//   globalRate: 1.5         <- статическое поле
// }]
//
// СТЕК:
// [counter1] -> 0x1000
// [counter2] -> 0x2000
//
// КУЧА (0x1000):
// [GlobalCounter объект {
//   instanceCount: 0        <- примитив в куче
// }]
//
// КУЧА (0x2000):
// [GlobalCounter объект {
//   instanceCount: 0        <- примитив в куче
// }]

Полное резюме по местоположению

public class StorageExample {
    // 1. СТАТИЧЕСКОЕ ПРИМИТИВНОЕ ПОЛЕ
    static int staticInt = 42;      // -> METASPACE
    
    // 2. СТАТИЧЕСКОЕ ССЫЛОЧНОЕ ПОЛЕ
    static String staticString = "test"; // ссылка -> METASPACE, объект -> КУЧА
    
    // 3. ЭКЗЕМПЛЯРНОЕ ПРИМИТИВНОЕ ПОЛЕ
    private int instanceInt = 100;  // -> КУЧА (внутри объекта)
    
    // 4. ЭКЗЕМПЛЯРНОЕ ССЫЛОЧНОЕ ПОЛЕ
    private String instanceString = "value"; // ссылка -> КУЧА, объект -> КУЧА
    
    public void localVariables() {
        // 5. ЛОКАЛЬНОЕ ПРИМИТИВНОЕ ПОЛЕ
        int localInt = 200;         // -> СТЕК
        
        // 6. ЛОКАЛЬНАЯ ССЫЛКА
        String localString = "local"; // ссылка -> СТЕК, объект -> КУЧА
    }
}

// ИТОГОВАЯ ТАБЛИЦА:
//
// Переменная               | Примитив хранится | Ссылка хранится
// ─────────────────────────┼──────────────────┼─────────────────
// Статическое поле         | METASPACE        | METASPACE
// Экземплярное поле        | КУЧА (в объекте) | КУЧА (в объекте)
// Локальная переменная     | СТЕК             | СТЕК

Важное уточнение: примитивы в объектах ВСЕГДА в куче

public class Demo {
    private int value = 42;  // примитив
    
    public void test() {
        // ОШИБКА В ПОНИМАНИИ: примитив НЕ на стеке
        // Это экземплярное поле, поэтому оно в КУЧЕ
        
        int localValue = 42;  // ЭТОТ примитив на СТЕКЕ
        
        Demo obj = new Demo();
        // obj.value - это примитив в куче (внутри объекта)
        // localValue - это примитив на стеке
    }
}

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

public class User {
    // Статическое поле
    static int totalUsers = 0;  // Metaspace
    
    // Экземплярные поля
    private int id;             // Куча
    private int age;            // Куча
    private String name;        // Ссылка в куче, объект в куче
    private long createdTime;   // Куча
}

public class MemoryAnalysis {
    public static void main(String[] args) {
        // Локальная переменная (ссылка) - на стеке
        User user1 = new User();  // user1 -> СТЕК, объект -> КУЧА
        User user2 = new User();  // user2 -> СТЕК, объект -> КУЧА
        
        // Локальная переменная (примитив) - на стеке
        int count = 2;  // count -> СТЕК
        
        // РАСПРЕДЕЛЕНИЕ В ПАМЯТИ:
        //
        // METASPACE:
        // User.totalUsers = 0
        //
        // СТЕК (главный поток):
        // [user1] = 0xA000
        // [user2] = 0xB000
        // [count] = 2
        //
        // КУЧА:
        // 0xA000: User {
        //   id: 0
        //   age: 0
        //   name: 0xC000
        //   createdTime: 0
        // }
        // 0xB000: User {
        //   id: 0
        //   age: 0
        //   name: 0xD000
        //   createdTime: 0
        // }
        // 0xC000: String
        // 0xD000: String
    }
}

Массивы примитивов

public class ArrayExample {
    // Статический массив примитивов - массив в Metaspace
    static int[] staticArray = {1, 2, 3};
    
    // Экземплярный массив примитивов - массив в куче
    private int[] instanceArray = {4, 5, 6};
    
    public void methodWithLocalArray() {
        // Локальный массив - ссылка на стеке, массив в куче
        int[] localArray = {7, 8, 9};
        
        // ПАМЯТЬ:
        // СТЕК: [localArray] -> адрес 0xE000
        // КУЧА (0xE000): [7, 8, 9]
    }
}

Оптимизация: стек быстрее куч

public class Performance {
    public void example1() {
        // Примитив на стеке - очень быстро
        int a = 10;
        int b = 20;
        int c = a + b;  // Все операции на стеке - нет GC
    }
    
    public void example2() {
        // Объект в куче - медленнее
        Integer a = 10;  // Объект Integer в куче
        Integer b = 20;  // Объект Integer в куче
        Integer c = a + b;  // Распаковка -> операция -> упаковка
                            // GC может потребоваться
    }
}

Заблуждение: примитивы НЕ всегда на стеке

public class Misconception {
    // НЕПРАВДА: примитив на стеке
    private int field = 10;  // ЛОЖЬ! На стеке только ссылка на object
                             // Сам примитив в КУЧЕ (внутри объекта)
    
    public void method() {
        // ПРАВДА: примитив на стеке
        int local = 10;      // ИСТИНА! На стеке
    }
}

Вывод

Экземплярные примитивные поля хранятся в КУЧЕ - конкретно, они входят в состав объекта в куче.

Статические примитивные поля хранятся в METASPACE - это глобальные данные класса.

Локальные примитивные переменные хранятся на СТЕКЕ - в фрейме текущего метода.

Ключевое правило: если это часть объекта (экземплярное поле), оно хранится вместе с объектом в куче. Стек используется только для локальных переменных методов и ссылок на объекты.