Что такое куча в java

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

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

Java Heap память

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

Stack память в Java

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

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

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

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

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

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

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

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

Источник

Java-модель памяти (часть 1)

Привет, Хабр! Представляю вашему вниманию перевод первой части статьи «Java Memory Model» автора Jakob Jenkov.

Прохожу обучение по Java и понадобилось изучить статью Java Memory Model. Перевёл её для лучшего понимания, ну а чтоб добро не пропадало решил поделиться с сообществом. Думаю, для новичков будет полезно, и если кому-то понравится, то переведу остальное.

Первоначальная Java-модель памяти была недостаточно хороша, поэтому она была пересмотрена в Java 1.5. Эта версия модели все ещё используется сегодня (Java 14+).

Внутренняя Java-модель памяти

Java-модель памяти, используемая внутри JVM, делит память на стеки потоков (thread stacks) и кучу (heap). Эта диаграмма иллюстрирует Java-модель памяти с логической точки зрения:

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Каждый поток, работающий в виртуальной машине Java, имеет свой собственный стек. Стек содержит информацию о том, какие методы вызвал поток. Я буду называть это «стеком вызовов». Как только поток выполняет свой код, стек вызовов изменяется.

Стек потока содержит все локальные переменные для каждого выполняемого метода. Поток может получить доступ только к своему стеку. Локальные переменные, невидимы для всех других потоков, кроме потока, который их создал. Даже если два потока выполняют один и тот же код, они всё равно будут создавать локальные переменные этого кода в своих собственных стеках. Таким образом, каждый поток имеет свою версию каждой локальной переменной.

Все локальные переменные примитивных типов (boolean, byte, short, char, int, long, float, double) полностью хранятся в стеке потоков и не видны другим потокам. Один поток может передать копию примитивной переменной другому потоку, но не может совместно использовать примитивную локальную переменную.

Куча содержит все объекты, созданные в вашем приложении, независимо от того, какой поток создал объект. К этому относятся и версии объектов примитивных типов (например, Byte, Integer, Long и т.д.). Неважно, был ли объект создан и присвоен локальной переменной или создан как переменная-член другого объекта, он хранится в куче.

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

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Локальная переменная может быть примитивного типа, в этом случае она полностью хранится в стеке потока.

Локальная переменная также может быть ссылкой на объект. В этом случае ссылка (локальная переменная) хранится в стеке потоков, но сам объект хранится в куче.

Объект может содержать методы, и эти методы могут содержать локальные переменные. Эти локальные переменные также хранятся в стеке потоков, даже если объект, которому принадлежит метод, хранится в куче.

Переменные-члены объекта хранятся в куче вместе с самим объектом. Это верно как в случае, когда переменная-член имеет примитивный тип, так и в том случае, если она является ссылкой на объект.

Статические переменные класса также хранятся в куче вместе с определением класса.

К объектам в куче могут обращаться все потоки, имеющие ссылку на объект. Когда поток имеет доступ к объекту, он также может получить доступ к переменным-членам этого объекта. Если два потока вызывают метод для одного и того же объекта одновременно, они оба будут иметь доступ к переменным-членам объекта, но каждый поток будет иметь свою собственную копию локальных переменных.

Диаграмма, которая иллюстрирует описанное выше:

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Два потока имеют набор локальных переменных. Local Variable 2 указывает на общий объект в куче (Object 3). Каждый из потоков имеет свою копию локальной переменной со своей ссылкой. Их ссылки являются локальными переменными и поэтому хранятся в стеках потоков. Тем не менее, две разные ссылки указывают на один и тот же объект в куче.

Обратите внимание, что общий Object 3 имеет ссылки на Object 2 и Object 4 как переменные-члены (показано стрелками). Через эти ссылки два потока могут получить доступ к Object 2 и Object 4.

На диаграмме также показана локальная переменная (Local variable 1). Каждая её копия содержит разные ссылки, которые указывают на два разных объекта (Object 1 и Object 5), а не на один и тот же. Теоретически оба потока могут обращаться как к Object 1, так и к Object 5, если они имеют ссылки на оба этих объекта. Но на диаграмме выше каждый поток имеет ссылку только на один из двух объектов.

Итак, мы посмотрели иллюстрацию, теперь давайте посмотрим, как тоже самое выглядит в Java-коде:

Метод run() вызывает methodOne(), а methodOne() вызывает methodTwo().

methodOne() объявляет примитивную локальную переменную (localVariable1) типа int и локальную переменную (localVariable2), которая является ссылкой на объект.

Каждый поток, выполняющий методOne(), создаст свою собственную копию localVariable1 и localVariable2 в своих соответствующих стеках. Переменные localVariable1 будут полностью отделены друг от друга, находясь в стеке каждого потока. Один поток не может видеть, какие изменения вносит другой поток в свою копию localVariable1.

Каждый поток, выполняющий методOne(), также создает свою собственную копию localVariable2. Однако две разные копии localVariable2 в конечном итоге указывают на один и тот же объект в куче. Дело в том, что localVariable2 указывает на объект, на который ссылается статическая переменная sharedInstance. Существует только одна копия статической переменной, и эта копия хранится в куче. Таким образом, обе копии localVariable2 в конечном итоге указывают на один и тот же экземпляр MySharedObject. Экземпляр MySharedObject также хранится в куче. Он соответствует Object 3 на диаграмме выше.

Обратите внимание, что класс MySharedObject также содержит две переменные-члены. Сами переменные-члены хранятся в куче вместе с объектом. Две переменные-члены указывают на два других объекта Integer. Эти целочисленные объекты соответствуют Object 2 и Object 4 на диаграмме.

Также обратите внимание, что methodTwo() создает локальную переменную с именем localVariable1. Эта локальная переменная является ссылкой на объект типа Integer. Метод устанавливает ссылку localVariable1 для указания на новый экземпляр Integer. Ссылка будет храниться в своей копии localVariable1 для каждого потока. Два экземпляра Integer будут сохранены в куче и, поскольку метод создает новый объект Integer при каждом выполнении, два потока, выполняющие этот метод, будут создавать отдельные экземпляры Integer. Они соответствуют Object 1 и Object 5 на диаграмме выше.

Обратите также внимание на две переменные-члены в классе MySharedObject типа long, который является примитивным типом. Поскольку эти переменные являются переменными-членами, они все еще хранятся в куче вместе с объектом. В стеке потоков хранятся только локальные переменные.

Источник

Развеиваем мифы об управлении памятью в JVM

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Структура памяти JVM

Сначала давайте посмотрим на структуру памяти JVM. Эта структура применяется начиная с JDK 11. Вот какая память доступна процессу JVM, она выделяется операционной системой:

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Это нативная память, выделяемая ОС, и её размер зависит от системы, процессор и JRE. Какие области и для чего предназначены?

Куча (heap)

Здесь JVM хранит объекты и динамические данные. Это самая крупная область памяти, в ней работает сборщик мусора. Размером кучи можно управлять с помощью флагов Xms (начальный размер) и Xmx (максимальный размер). Куча не передаётся виртуальной машине целиком, какая-то часть резервируется в качестве виртуального пространства, за счёт которого куча может в будущем расти. Куча делится на пространства «молодого» и «старого» поколения.

Стеки потоков исполнения

Метапространство

Кеш кода

Здесь компилятор Just In Time (JIT) хранит скомпилированные блоки кода, к которым приходится часто обращаться. Обычно JVM интерпретирует байткод в нативный машинный код, однако код, скомпилированный JIT-компилятором, не нужно интерпретировать, он уже представлен в нативном формате и закеширован в этой области памяти.

Общие библиотеки

Здесь хранится нативный код для любых общих библиотек. Эта область памяти загружается операционной системой лишь один раз для каждого процесса.

Использование памяти JVM: стек и куча

Теперь давайте посмотрим, как исполняемая программа использует самые важные части памяти. Воспользуемся нижеприведённым кодом. Он не оптимизирован с точки зрения корректности, так что игнорируйте проблемы вроде ненужных промежуточных переменных, некорректных модификаторов и прочего. Его задача — визуализировать использование стека и кучи.

Здесь вы можете увидеть, как исполняется вышеприведённая программа и как используются стек и куча:

Управление памятью JVM: сборка мусора

Давайте разберёмся с автоматическим управлением кучей, которое играет очень важную роль с точки зрения производительности приложения. Когда программа пытается выделить в куче больше памяти, чем доступно (в зависимости от значения Xmx ), мы получаем ошибки нехватки памяти.

JVM управляет куче с помощью сборки мусора. Чтобы освободить место для создания нового объекта, JVM очищает память, занятую потерянными объектами, то есть объектами, на которые больше нет прямых или опосредованных ссылок из стека.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Сборщик мусора в JVM отвечает за:

Сборщик мусора Mark & Sweep

JVM использует отдельный поток демона, который работает в фоне для сборки мусора. Этот процесс запускается при выполнении определённых условий. Сборщик Mark & Sweep обычно работает в два этапа, иногда добавляют третий, в зависимости от используемого алгоритма.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

JVM предлагает на выбор несколько разных алгоритмов сборки мусора, и в зависимости от вашего JDK может быть ещё больше вариантов (например, сборщик Shenandoah в OpenJDK). Авторы разных реализаций стремятся к разным целям:

Сборщики в JDK 11

Процесс сборки мусора

Вне зависимости от того, какой выбран сборщик, в JVM используется два вида сборки — младший и старший сборщик.

Младший сборщик

Он поддерживает чистоту и компактность пространства молодого поколения. Запускается тогда, когда JVM не может получить в раю необходимую память для размещения нового объекта. Изначально все области кучи пусты. Рай заполняется первым, за ним область выживших, и в конце хранилище.

Здесь вы можете увидеть процесс работы этого сборщика:

Старший сборщик

Следит за чистотой и компактностью пространства старого поколения (хранилищем). Запускается при одном из таких условий:

Заключение

Мы рассмотрели структуру и управление памятью JVM. Это не исчерпывающая статья, мы не говорили о многих более сложных концепциях и способах настройки под особые сценарии использования. Подробнее вы можете почитать здесь.

Но для большинства JVM-разработчиков (Java, Kotlin, Scala, Clojure, JRuby, Jython) этого объёма информации будет достаточно. Надеюсь, теперь вы сможете писать более качественный код, создавать более производительные приложения, избегая различных проблем с утечкой памяти.

Источник

Стек, очередь и куча

На рисунке вы можете видеть обобщенную модель организации памяти компьютера.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Стек — это область памяти, которую вы, как программист, не контролируете никоим образом. В неё записываются переменные и информация, которые создаются в результате вызова любых функций. Когда функция заканчивает работу, то вся информация о ее вызов и ее переменные удаляются из стека автоматически.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Но важнее даже не это, а то, что стек — это структура данных, которая работает по принципу «последним пришел — первым ушел» (last in first out, LIFO). На лекции Дэвид предложил представление стека, как стопки подносов в столовой. Поднос, который попал в стопку последним, новый клиент столовой возьмет в первую очередь.

Над стеком можно осуществлять две операции: push (занесение данных) и pop (изъятие данных).

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Пример реализации стека языке С приведен ниже. В этом примере, стек — это просто массив строк, имеет определенную емкость (CAPACITY), и текущий размер (size):

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Для реализации операции pop, необходимо проверить, не пустой стек, уменьшить текущий размер на единицу и вернуть элемент.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Очередь

Очередь (queue) — это структура данных, которая напоминает обычную очередь. То есть, в отличие от стека, она работает по принципу «первым пришел — первым ушел» (first in first out, FIFO).

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Для очереди определены две операции: добавление элемента в конец очереди (enqueue) и изъятие элемента с начала очереди (dequeue).

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

В примере объявлена очередь, которая, по сути, представляет собой массив строк:

Чтобы реализовать операцию enqueue, необходимо убедиться, что очередь, не переполнена, добавить элемент в конец очереди и увеличить текущий размер на единицу.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Чтобы реализовать операцию dequeue, надо убедиться, что очередь не пуста, увеличить head на единицу, уменьшить текущий размер и вернуть первый элемент очереди.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Куча и переполнение буфера

Куча (heap) — область памяти, которую контролируют непосредственно программисты. Над которой вы, как программисты, получаете непосредственный контроль. Память здесь выделяется в результате вызова функции malloc.

Более глубокие знания о стеке и куче вам пока не понадобятся. Вы их получите позже, если захотите изучать программирование и компьютерные науки глубже.

Буфер — это массив определенной длины, расположенный в памяти. Переполнение буфера (buffer overflow) возникает, если мы пытаемся записать в него больше данных, чем предусмотрено размером этого массива. С помощью переполнения буфера злоумышленник может записать опасный код в память компьютера.

Источник

Избавляемся от мусора в Java

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в java

Что такое сборка мусора, зачем она нужна и как работает

Для работы любого приложения требуется память. Однако память компьютера ограничена. Поэтому важно ее очищать от старых неиспользуемых данных, чтобы освободить место для новых.

Кто занимается этой очисткой? Как и когда очищается память? Как выглядит структура памяти? Давайте разберем с этим подробнее.

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

Память в Java состоит из следующих областей:

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в javaСтруктура памяти Java

Native Memory — вся доступная системная память.

Stack (стек) — используется для хранения локальных переменных и стека вызовов метода. Для каждого потока выделяется свой стек.

Metaspace (метаданные) — в этой памяти хранятся метаданные классов и статические переменные. Это пространство также является общими для всех. Так как metaspace является частью native memory, то его размер зависит от платформы. Верхний предел объема памяти, используемой для metaspace, можно настроить с помощью флага MaxMetaspaceSize.

PermGen (Permanent Generation, постоянное поколение) присутствовало до Java 7. Начиная с Java 8 ему на смену пришла область Metaspace.

CodeCache (кэш кода) — JIT-компилятор компилирует часто исполняемый код, преобразует его в нативный машинный код и кеширует для более быстрого выполнения. Это тоже часть native memory.

Сборка мусора: введение

Что такое «мусор»? Мусором считается объект, который больше не может быть достигнут по ссылке из какого-либо объекта. Поскольку такие объекты больше не используются в приложении, то их можно удалить из памяти.

Например, на диаграмме ниже объект fruit2 может быть удален из памяти, поскольку на него нет ссылок.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в javaМусор

Что такое сборка мусора? Сборка мусора — это процесс автоматического управления памятью. Освобождение памяти (путем очистки мусора) выполняется автоматически специальным компонентом JVM — сборщиком мусора (Garbage Collector, GC). Нам, как программистам, нет необходимости вмешиваться в процесс сборки мусора.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в javaИсточник: Oracle.com

Сборка мусора: процесс

Для сборки мусора используется алгоритм пометок (Mark & Sweep). Этот алгоритм состоит из трех этапов:

Sweep (очистка). На этом шаге освобождается память, занятая объектами, не отмеченными на предыдущем шаге.

Compact (уплотнение). Объекты, пережившие очистку, перемещаются в единый непрерывный блок памяти. Это уменьшает фрагментацию кучи и позволяет проще и быстрее размещать новые объекты.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в javaMark & Sweep GC

Поколения объектов

Что такое поколения объектов?

Для оптимизации сборки мусора память кучи дополнительно разделена на четыре области. В эти области объекты помещаются в зависимости от их возраста (как долго они используются в приложении).

Young Generation (молодое поколение). Здесь создаются новые объекты. Область young generation разделена на три части раздела: Eden (Эдем), S0 и S1 (Survivor Space — область для выживших).

Old Generation (старое поколение). Здесь хранятся давно живущие объекты.

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в javaПоколения в куче

Что такое Stop the World?

Когда запускается этап mark, работа приложения останавливается. После завершения mark приложение возобновляет свою работу. Любая сборка мусора — это «Stop the World».

Что такое гипотеза о поколениях?

Как уже упоминалось ранее, для оптимизации этапов mark и sweep используются поколения. Гипотеза о поколениях говорит о следующем:

Большинство объектов живут недолго.

Если объект выживает, то он, скорее всего, будет жить вечно.

Этапы mark и sweep занимают меньше времени при большом количестве мусора. То есть маркировка будет происходить быстрее, если анализируемая область небольшая и в ней много мертвых объектов.

Таким образом, алгоритм сборки мусора, использующий поколения, выглядит следующим образом:

Что такое куча в java. Смотреть фото Что такое куча в java. Смотреть картинку Что такое куча в java. Картинка про Что такое куча в java. Фото Что такое куча в javaСборка мусора поколениями

    Новые объекты создаются в области Eden. Области Survivor (S0, S1) на данный момент пустые.

    Когда область Eden заполняется, происходит минорная сборка мусора (Minor GC). Minor GC — это процесс, при котором операции mark и sweep выполняются для young generation (молодого поколения).

    После Minor GC живые объекты перемещаются в одну из областей Survivor (например, S0). Мертвые объекты полностью удаляются.

    По мере работы приложения пространство Eden заполняется новыми объектами. При очередном Minor GC области young generation и S0 очищаются. На этот раз выжившие объекты перемещаются в область S1, и их возраст увеличивается (отметка о том, что они пережили сборку мусора).

    При следующем Minor GC процесс повторяется. Однако на этот раз области Survivor меняются местами. Живые объекты перемещаются в S0 и у них увеличивается возраст. Области Eden и S1 очищаются.

    Объекты между областями Survivor копируются определенное количество раз (пока не переживут определенное количество Minor GC) или пока там достаточно места. Затем эти объекты копируются в область Old.

    Major GC. При Major GC этапы mark и sweep выполняются для Old Generation. Major GC работает медленнее по сравнению с Minor GC, поскольку старое поколение в основном состоит из живых объектов.

    Преимущества использования поколений

    Minor GC происходит в меньшей части кучи (

    2/3 от кучи). Этап маркировки эффективен, потому что область небольшая и состоит в основном из мертвых объектов.

    Недостатки использования поколений

    В каждый момент времени одно из пространств Survivor (S0 или S1) пустое и не используется.

    Сборка мусора: флаги

    В этом разделе приведены некоторые важные флаги, которые можно использовать для настройки процесса сборки мусора.

    Флаг

    Описание

    Первоначальный размер кучи

    Максимальный размер куча

    Отношение размера Old Generation к Young Generation

    Отношение размера Eden к Survivor

    Возраст объекта, когда объект перемещается из области Survivor в область Old Generation

    Типы сборщиков мусора

    Сборщик мусора

    Описание

    Преимущества

    Когда использовать

    Флаги для включения

    Использует один поток.

    Эффективный, т.к. нет накладных расходов на взаимодействие потоков.

    Работа с небольшими наборами данных.

    Использует несколько потоков.

    Многопоточность ускоряет сборку мусора.

    В приоритете пиковая производительность.

    Допустимы паузы при GC в одну секунду и более.

    Работа со средними и большими наборами данных.

    Для приложений, работающих на многопроцессорном или многопоточном оборудовании.

    Выполняет некоторую тяжелую работу параллельно с работой приложения.

    Может использоваться как на небольших системах, так и на больших с большим количеством процессоров и большим количеством памяти.

    Когда время отклика важнее пропускной способности.

    Паузы GC должны быть меньше одной секунды.

    Выполняет всю тяжелую работу параллельно с работой приложения.

    В приоритете время отклика.

    Сборщики мусора в Java

    Инструменты мониторинга GC

    Что мониторить?

    Частота запуска сборки мусора. Так как GC вызывает «stop the world», поэтому чем время сборки мусора меньше, тем лучше.

    Длительность одного цикла сборки мусора.

    Как мониторить сборщик мусора?

    Для мониторинга можно использовать следующие инструменты:

    Для включения логирования событий сборщика мусора добавьте следующие параметры JVM:

    Источник

    Добавить комментарий

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