Стек пам’яті та простору купи в Java

1. Вступ

Щоб запустити програму оптимальним чином, JVM ділить пам’ять на стекову та кучу пам’яті. Кожного разу, коли ми оголошуємо нові змінні та об'єкти, викликаємо новий метод, оголошуємо String або виконуємо подібні операції, JVM призначає пам'ять для цих операцій або з пам'яті стека, або з кучи простору.

У цьому підручнику ми обговоримо ці моделі пам'яті. Ми перелічимо деякі ключові відмінності між ними, як вони зберігаються в оперативній пам’яті, функції, які вони пропонують, і де їх використовувати.

2. Стек пам'яті в Java

Пам'ять стека в Java використовується для виділення статичної пам'яті та виконання потоку. Він містить примітивні значення, які є специфічними для методу, і посилання на об'єкти, що знаходяться в купі, згадані з методу.

Доступ до цієї пам’яті здійснюється у порядку “останній перший вийшов” (LIFO). Щоразу, коли викликається новий метод, створюється новий блок зверху стека, який містить значення, характерні для цього методу, такі як примітивні змінні та посилання на об'єкти.

Коли метод завершує виконання, відповідний кадр стека змивається, потік повертається до виклику методу, і простір стає доступним для наступного методу.

2.1. Основні характеристики стекової пам'яті

Окрім того, що ми обговорювали дотепер, нижче наведено деякі інші особливості стекової пам'яті:

  • Він зростає і зменшується, оскільки нові методи викликаються і повертаються відповідно
  • Змінні всередині стеку існують лише до тих пір, поки працює метод, який їх створив
  • Він автоматично розподіляється та звільняється, коли метод завершує виконання
  • Якщо ця пам'ять заповнена, Java видає java.lang.StackOverFlowError
  • Доступ до цієї пам'яті швидкий, якщо порівнювати з кучевою пам’яттю
  • Ця пам’ять безпечна для потоків, оскільки кожен потік працює у своєму власному стеку

3. Простір купи в Java

Простір купи в Java використовується для динамічного розподілу пам'яті для об'єктів Java та класів JRE під час виконання . Нові об'єкти завжди створюються в просторі купи, а посилання на ці об'єкти зберігаються в пам'яті стека.

Ці об’єкти мають глобальний доступ і доступ до них можна отримати з будь-якої точки програми.

Дана модель пам'яті розбита на більш дрібні частини, які називаються поколіннями, це:

  1. Молоде покоління - тут виділяються і старіють усі нові об’єкти. Незначний збір сміття відбувається, коли він заповнюється
  2. Старе або засноване покоління - тут зберігаються давно вижилі предмети. Коли об’єкти зберігаються в молодому поколінні, встановлюється поріг віку об’єкта, а коли цей поріг досягається, об’єкт переміщується до старого покоління
  3. Постійне покоління - воно складається з метаданих JVM для класів середовища виконання та методів застосування

Ці різні частини також обговорюються в цій статті - Різниця між JVM, JRE та JDK.

Ми завжди можемо маніпулювати розміром купи пам'яті відповідно до наших вимог. Для отримання додаткової інформації відвідайте цю пов’язану статтю Baeldung.

3.1. Основні характеристики Java Heap Memory

Окрім того, що ми обговорювали дотепер, нижче наведено деякі інші особливості простору купи:

  • Доступ до нього здійснюється за допомогою складних методів управління пам’яттю, які включають молоде покоління, старе або постійне покоління та постійне покоління
  • Якщо куча місця заповнена, Java видає java.lang.OutOfMemoryError
  • Доступ до цієї пам'яті відносно повільніший, ніж пам'ять стека
  • Ця пам'ять, на відміну від стека, не вивільняється автоматично. Щоб звільнити невикористані об’єкти, щоб зберегти ефективність використання пам’яті, йому потрібен Garbage Collector
  • На відміну від стека, купа не є безпечною для потоків і її потрібно захищати, правильно синхронізуючи код

4. Приклад

Виходячи з того, що ми дізналися на даний момент, давайте проаналізуємо простий код Java і оцінимо, як тут управляється пам'яттю:

class Person { int id; String name; public Person(int id, String name) { this.id = id; this.name = name; } } public class PersonBuilder { private static Person buildPerson(int id, String name) { return new Person(id, name); } public static void main(String[] args) { int id = 23; String name = "John"; Person person = null; person = buildPerson(id, name); } }

Давайте проаналізуємо цей крок за кроком:

  1. Після введення методу main () створюється простір у пам'яті стека для зберігання примітивів та посилань на цей метод
    • Примітивне значення цілочисельного ідентифікатора буде зберігатися безпосередньо в пам'яті стека
    • Посилальна змінна person типу Person також буде створена в пам'яті стека, яка вказуватиме на фактичний об'єкт у купі
  2. Виклик параметризованого конструктора Person (int, String) з main () виділить додаткову пам'ять поверх попереднього стека. Тут буде зберігатися:
    • Посилання на цей об'єкт викликаючого об'єкта в пам'яті стека
    • Елементарне значення ID в пам'яті стека
    • Згадка змінної Струнний аргумент імені , яке буде вказувати на реальну рядок з рядка пулу в динамічної пам'яті
  3. Основний спосіб додатково виклику buildPerson () статичний метод, для якого подальший розподіл матиме місце в пам'яті стека на верхній частині попереднього. Це знову збереже змінні способом, описаним вище.
  4. Однак для новоствореної об'єктної особи типу Person всі змінні екземпляра будуть зберігатися в купі пам'яті.

Цей розподіл пояснюється на цій схемі:

5. Підсумок

Перш ніж закінчити цю статтю, давайте швидко узагальнимо відмінності між пам'яттю стека та простором купи:

Параметр Пам'ять стека Простір купи
Застосування Стек використовується по частинах, по одній під час виконання нитки Весь додаток використовує кучу простору під час виконання
Розмір Стек має обмеження розміру в залежності від ОС і, як правило, менше, ніж Heap Немає обмежень розміру для купи
Зберігання Зберігає лише примітивні змінні та посилання на об'єкти, створені в кучевому просторі Тут зберігаються всі новостворені об'єкти
Порядок До нього доступ здійснюється за допомогою системи розподілу пам’яті Last-in First-out (LIFO) Доступ до цієї пам’яті здійснюється за допомогою складних методів управління пам’яттю, які включають молоде покоління, старе або постійне покоління та постійне покоління.
Життя Пам'ять стека існує лише до тих пір, поки працює поточний метод Простір купи існує до тих пір, поки працює програма
Ефективність Порівняно набагато швидше розподілити в порівнянні з купою Повільніше розподіляти в порівнянні зі стеком
Розподіл / Виділення Ця пам'ять автоматично виділяється та звільняється, коли метод викликається та повертається відповідно Простір купи виділяється, коли нові об’єкти створюються та вивільняються Gargabe Collector, коли на них більше немає посилань

6. Висновок

Стек і купа - це два способи виділення пам'яті Java. У цій статті ми зрозуміли, як вони працюють і коли використовувати їх для розробки кращих програм Java.

Щоб дізнатись більше про управління пам’яттю в Java, перегляньте цю статтю тут. Ми також обговорили збирач сміття JVM, про який коротко йдеться в цій статті.