Что такое Heap и Stack память в Java?

Что такое Heap и Stack память в Java?

В Java есть такие понятия как Heap и Stack память. Сегодня мы узнаем разницу между ними и зачем они нужны. Как всегда, сначала в теории и затем на практике разберем эту сложную тему.

Java Heap память

Java Heap (куча) используется Java Runtime для выделения памяти под объекты и JRE классы. Создание нового объекта также происходит в куче. Здесь работает сборщик мусора: освобождает память путем удаления объектов, на которые нет каких-либо ссылок. Любой объект, созданный в куче, имеет глобальный доступ и на него могут ссылаться с любой части приложения.

Stack память в Java

Стековая память в Java работает по схеме LIFO (Последний-зашел-Первый-вышел). Всякий раз, когда вызывается метод, в памяти стека создается новый блок, который содержит примитивы и ссылки на другие объекты в методе. Как только метод заканчивает работу, блок также перестает использоваться, тем самым предоставляя доступ для следующего метода.
Размер стековой памяти намного меньше объема памяти в куче.

Давайте рассмотрим отличия стековой памяти и кучи на примере простой программы.

На картинке ниже представлена память стека и кучи для программы выше

Java Heap Java Stack - javadevblog.com

А теперь рассмотри шаги выполнения нашей программы:

  1. Как только мы запустим программу, загружаются все классы среды выполнения в кучу. Потом  метод main()находит строку 1 и Java Runtime создает стековую память для использования методом main().
  2. Далее в строке 2 создается int’овая переменная, которая хранится в памяти стека метода main().
  3. Потом мы создали объект в строке 3 и он тут же появляется в куче, а стековая память содержит ссылку на него. Точно такой же процесс происходит, когда мы создаем объект Memory в строке 4.
  4. Теперь в строке 5 мы вызываем метод exMethod() и тут же сразу создается блок на вершине стека, который будет использоваться этим методом. Поскольку в Java объекты и примитивы передаются по значению, то в строке 6 будет создана новая ссылка на объект, созданный в строке 3.
  5. Строка, созданная в строке 7, отправляется в Пул строк (String Pool), который находится в куче. На эту строку также создается ссылка в стековой памяти метода exMethod().
  6. Метод exMethod()завершается на строке 8, поэтому блок стековой памяти для этого метода становится свободным.
  7. В строке 9 метод main() завершается, поэтому стековая память для метода main() будет уничтожена. Также программа заканчивается в этой строке, следовательно, Java Runtime освобождает всю память и завершает программу.

Разница между Stack и Heap памятью в Java

На основании приведенных выше объяснений, мы можем легко подытожить следующие различия между Heap и Stack памятью в Java.

  • Куча используется всеми частями приложения в то время как стек используется только одним потоком исполнения программы.
  • Всякий раз, когда создается объект, он всегда хранится в куче, а в памяти стека содержится ссылка на него. Память стека содержит только локальные переменные примитивных типов и ссылки на объекты в куче.
  • Объекты в куче доступны с любой точки программы, в то время как стековая память не может быть доступна для других потоков.
  • Управление памятью в стеке осуществляется по схеме LIFO.
  • Стековая память существует лишь какое-то время работы программы, а память в куче живет с самого начала до конца работы программы.
  • Мы можем использовать -Xms и -Xmx опции JVM, чтобы определить начальный и максимальный размер памяти в куче. Для стека определить размер памяти можно с помощью опции -Xss .
  • Если память стека полностью занята, то Java Runtime бросает java.lang.StackOverflowError, а если память кучи заполнена, то бросается исключение java.lang.OutOfMemoryError: Java Heap Space.
  • Размер памяти стека намного меньше памяти в куче. Из-за простоты распределения памяти (LIFO), стековая память работает намного быстрее кучи.

Вот и все, что нужно знать о Stack и Heap памяти в Java. Следите за обновлениями в разделе Полезности.

13 thoughts to “Что такое Heap и Stack память в Java?”

  1. Вечер добрый! У вас есть в коде присутствует ошибка, из-за чего возможно затруднение понимания начинающими программистами.
    Ваша строка
    mem.exMethod(obj);
    заменяется на
    memory.exMethod(object);

  2. Stack — это часть Permanent Generation (а начиная с java 8 — часть Metaspace ), верно? или я неправильно понимаю?

  3. Опечатка в строке «Поскольку Java передает параметры по значению». Объекты передаются по ссылке, а примитивы по значению. В примере передается объект, соответственно по ссылке.

    1. В Java всё передается по значению.Цитата из Хорстмана «В языке Java всегда используется только вызов по значению. Это означает, что
      метод получает копии значений всех своих параметров. По этой причине метод не
      может видоизменить содержимое ни одной из переменных, передаваемых ему в качестве
      параметров.Некоторые программисты (и, к сожалению, даже авторы некоторых книг) утверждают, что в Java
      при передаче объектов используется вызов по ссылке. Но это совсем не так.»

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

        И в Вашем случае
        «Поскольку в Java объекты передаются по ссылке, а примитивы по значению, то в строке 6 будет создана новая ссылка на объект, созданный в строке 3.»

        описана именно передача по значению.

        Если бы передача проводилась по ссылке, то была бы возможность изменять объект строки 3 в функции «private void exMethod(Object param) { // строка 6» напрямую, через передаваемый в функцию параметр.

      2. «По этой причине метод не может видоизменить содержимое ни одной из переменных, передаваемых ему в качестве параметров.»

        это немножко запутывает… Стоит добавить , что в случае если в метод передается копия ссылки на объект(а не просто примитивное значение), то через нее метод МОЖЕТ изменять целевой объект.

  4. Всем привет. Ответьте пожалуйста на пару вопросов:
    1) А почему строка, созданная в строке 7, направится в пул строк, а не просто создастся новый объект? Вроде в пул строк же попадают только литералы.

    2) Тут приведены примеры без полей и методов класса. А где хранятся поля и методы класса: в стеке или в куче?

    1. 2) Поля объектов хранятся в куче. В стеке хранятся примитивные переменные методов или ссылки на не примитивные объекты в хипе, если переменная не является примитивом.

      1) Пул строк это вроде как хранилище внутри хранилища. Внутри хипа. В данном пуле лежит (будет лежать) значение, которое вернет метод toString(). Поскольку строка не примитив — то в методе exMethod есть лишь ссылка на хип, а точнее **на адрес нужной строки в пуле строк в хипе….**

  5. StackOverflowError и OutOfMemoryError не являются исключениями. Это даже из названия видно. И от Exception они соответственно не наследуются.

Добавить комментарий для Евгений Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *