Автор оригинала: Pankaj Kumar.
Некоторое время назад я написал пару постов о Сборке мусора Java и Java передается по значению . После этого я получил много писем с объяснениями о Пространстве кучи Java , Памяти стека Java , Распределении памяти в Java и в чем различия между ними.
Вы увидите много ссылок на память кучи и стека в Java, книгах и учебных пособиях по Java EE, но вряд ли найдете полное объяснение того, что такое память кучи и стека с точки зрения программы.
Пространство кучи Java
Пространство кучи Java используется средой выполнения java для выделения памяти объектам и классам JRE. Всякий раз, когда мы создаем объект, он всегда создается в пространстве кучи.
Сборка мусора выполняется в памяти кучи, чтобы освободить память, используемую объектами, на которые нет никаких ссылок. Любой объект, созданный в пространстве кучи, имеет глобальный доступ, и на него можно ссылаться из любого места приложения.
Память стека Java
Память стека Java используется для выполнения потока. Они содержат кратковременные значения для конкретного метода и ссылки на другие объекты в куче, на которые ссылается метод.
На стековую память всегда ссылаются в порядке LIFO (Последний вход-Первый выход). Всякий раз, когда вызывается метод, в памяти стека создается новый блок для метода, содержащий локальные значения примитивов и ссылки на другие объекты в методе.
Как только метод заканчивается, блок становится неиспользуемым и становится доступным для следующего метода. Размер стековой памяти очень меньше по сравнению с памятью кучи.
Кучная и стековая память в Java-программе
Давайте разберемся в использовании памяти кучи и стека с помощью простой программы.
package com.journaldev.test; public class Memory { public static void main(String[] args) { // Line 1 int i=1; // Line 2 Object obj = new Object(); // Line 3 Memory mem = new Memory(); // Line 4 mem.foo(obj); // Line 5 } // Line 9 private void foo(Object param) { // Line 6 String str = param.toString(); //// Line 7 System.out.println(str); } // Line 8 }
На приведенном ниже рисунке показана память стека и кучи со ссылкой на вышеуказанную программу и то, как они используются для хранения примитивов, объектов и ссылочных переменных.
Давайте пройдемся по этапам выполнения программы.
- Как только мы запускаем программу, она загружает все классы среды выполнения в пространство кучи. Когда метод main() найден в строке 1, среда выполнения Java создает память стека, которая будет использоваться потоком метода main ().
- Мы создаем примитивную локальную переменную в строке 2, поэтому она создается и хранится в памяти стека метода main ().
- Поскольку мы создаем объект в 3-й строке, он создается в памяти кучи, а память стека содержит ссылку на него. Аналогичный процесс происходит, когда мы создаем объект памяти в 4-й строке.
- Теперь, когда мы вызываем метод foo() в 5-й строке, создается блок в верхней части стека, который будет использоваться методом foo (). Поскольку Java передается по значению, в блоке стека foo() в 6-й строке создается новая ссылка на объект.
- Строка создается в 7-й строке, она помещается в пул Строк в пространстве кучи, и для нее создается ссылка в пространстве стека foo ().
- метод foo() завершается в 8-й строке, в это время блок памяти, выделенный для foo() в стеке, становится свободным.
- В строке 9 метод main() завершается, и память стека, созданная для метода main (), уничтожается. Кроме того, программа заканчивается на этой строке, следовательно, среда выполнения Java освобождает всю память и завершает выполнение программы.
Разница между пространством кучи Java и стековой памятью
Основываясь на приведенных выше объяснениях, мы можем легко сделать вывод о следующих различиях между памятью кучи и стека.
- Память кучи используется всеми частями приложения, в то время как память стека используется только одним потоком выполнения.
- Всякий раз, когда создается объект, он всегда хранится в пространстве кучи, а память стека содержит ссылку на него. Память стека содержит только локальные примитивные переменные и ссылочные переменные на объекты в пространстве кучи.
- Объекты, хранящиеся в куче, доступны глобально, в то время как память стека недоступна другим потокам.
- Управление памятью в стеке выполняется способом LIFO, в то время как в кучной памяти оно более сложное, поскольку используется глобально. Кучная память делится на молодое поколение, Старое поколение и т.д., Подробнее см. в Сборка мусора Java .
- Память стека недолговечна, в то время как память кучи живет от начала до конца выполнения приложения.
- Мы можем использовать опцию -Xms и -Xmx JVM для определения размера запуска и максимального размера кучи памяти. Мы можем использовать -Xss для определения размера стековой памяти.
- Когда память стека заполнена, среда выполнения Java выдает
java.lang.Ошибка StackOverflowError
в то время как если память кучи заполнена, она выдаетjava.lang.OutOfMemoryError: Пространство кучи Java
ошибка. - Размер стековой памяти очень меньше по сравнению с памятью кучи. Из-за простоты распределения памяти (LIFO) стековая память работает очень быстро по сравнению с памятью кучи.
Это все для Пространства кучи Java против стековой памяти с точки зрения java-приложения, я надеюсь, что это развеет ваши сомнения относительно выделения памяти при выполнении любой java-программы.
Список литературы: https://en.wikipedia.org/wiki/Java_memory_model https://blogs.oracle.com/jonthecollector/presenting-the-permanent-generation