Управление памятью в Java
⚡ Умное резюме
Управление памятью в Java объясняется, как JVM распределяет память во время выполнения между стеком, кучей и т. д. Codeа также статические области, как происходит передача ссылок на объекты во время вызовов методов и как сборщик мусора освобождает недоступные объекты, чтобы приложения оставались стабильными и свободными от утечек памяти.

Что такое стековая память в Java?
Стек памяти в Java Стек — это область памяти JVM, в которой хранятся кадры методов, локальные переменные и переменные-ссылки для каждого потока. Доступ к стеку всегда осуществляется в порядке «последний вошел — первый вышел», поэтому последний вызванный метод находится наверху, а его локальные переменные помещаются в стек и извлекаются из него вместе с кадром.
Каждая нить в Java Виртуальная машина получает собственный стек, который обеспечивает изоляцию вызовов методов и потокобезопасность по своей конструкции. Примитивные локальные переменные, такие как int, boolean и double, находятся непосредственно внутри стека, в то время как ссылки на объекты, хранящиеся в стеке, указывают на объекты, выделенные в куче.
Что такое куча памяти в Java?
Куча — это общая область памяти JVM, в которой хранится каждый элемент. Java Объект и массив создаются с помощью оператора `new`, а также любые переменные-ссылки, принадлежащие этим объектам, в качестве полей экземпляра. В отличие от стека, куча используется всеми потоками, поэтому доступ к объектам часто требует синхронизации.
Куча — это область, которой управляет сборщик мусора. В современных JVM HotSpot куча разделена на молодое поколение для объектов с коротким сроком жизни и старое поколение для объектов с длительным сроком жизни, при этом метаданные классов хранятся в отдельной собственной области, называемой метапространством.
Распределение памяти в Java
Распределение памяти в Java Это процесс, в ходе которого JVM выделяет области виртуальной памяти для переменных и экземпляров классов и структур во время выполнения программы. Память не выделяется объекту при его объявлении; создается только ссылка. Фактическое выделение памяти для объекта происходит с помощью оператора new, поэтому каждый объект находится в куче.
Java Выделение памяти разделено на следующие разделы:
- куча
- Стек
- Code
- статический
Такое разделение памяти необходимо для эффективного управления средой выполнения.
- Code В этом разделе содержится ваш скомпилированный байткодом.
- Стек секционные магазины методы, локальные переменные и эталонные переменные.
- куча раздел содержит объекты а также могут содержать ссылочные переменные, хранящиеся в качестве полей экземпляра.
- статический раздел содержит статические данные и статические методы общий для всех экземпляров.
Разница между локальной переменной и переменной экземпляра
Понимание того, где находятся переменные каждого типа в JVM, помогает объяснить поведение стека и кучи. переменная экземпляра объявлен внутри класса, но вне любого методаи оно существует в Куче как часть своего объекта.
class Student{ int num; // num is instance variable public void showData{}
A локальная переменная объявлен внутри метода, включая аргументы метода.и находится в стеке внутри активного фрейма.
public void sum(int a){ int x = a + 3; // a, x are local variables }
Разница между стеком и кучей
Стек и куча решают разные задачи внутри JVM. Стек обеспечивает каждому потоку быстрое и детерминированное выделение памяти для кратковременных данных, привязанных к области видимости метода, в то время как куча предоставляет общую область для долгоживущих объектов, на которые может ссылаться любой поток. В коротком видеоролике ниже кратко изложены различия между ними, после чего следует пошаговое руководство.
Нажмите здесь если видео недоступно
Чтобы увидеть, как взаимодействуют стек и куча, рассмотрим основной метод, который вызывает метод m1.
public void m1{ int x = 20; }
В стеке JVM для метода m1 создаётся кадр.
Переменная x в m1 также создается в фрейме для m1 в стеке, как показано на изображении ниже.
Затем метод m1 вызывает метод m2. В стеке создается новый кадр для метода m2 поверх кадра для метода m1.
Локальные переменные b и c также создаются внутри фрейма для m2 в стеке.
public void m2(int b){ boolean c; }
Далее, m2 вызывает метод m3. И снова, на вершине стека создается фрейм для m3, как показано ниже.
Теперь предположим, что метод m3 создает объект для класса Account, который содержит два элемента. переменные экземпляра int p и int q.
class Account { int p; int q; }
Вот код для метода m3.
public void m3(){ Account ref = new Account(); // more code }
Оператор `new Account()` создает объект типа `Account` в куче.
Переменная-ссылка ref создается в стеке внутри фрейма для m3.
Оператор присваивания заставляет переменную-ссылку указывать на объект в куче.
После завершения выполнения метода управление возвращается вызывающему методу, которым в данном случае является метод m2.
Кадр для метода m3 выгружается из стека.
Поскольку переменная-ссылка больше не указывает на объект в куче, этот объект становится доступным для сборки мусора.
После завершения работы метода m2 он удаляется из стека, и все его переменные становятся недоступными. То же самое происходит с методом m1, и в конечном итоге управление возвращается к основному методу.
Что произойдет, если объект будет использовать другую ссылку в качестве своей переменной экземпляра?
public static void main(String args[]) { A parent = new A(); // more code } class A { B child = new B(); int e; } class B { int c; int d; }
В этом случае переменная-ссылка child находится в куче как часть объекта A и, в свою очередь, указывает на свой собственный объект B, как показано ниже.
Что такое сбор мусора Java?
Сбор мусора в Java Это процесс, посредством которого JVM автоматически управляет памятью. Сборщик мусора находит объекты, которые больше недоступны из каких-либо активных ссылок, и освобождает их память. Динамическое выделение памяти происходит с помощью оператора new, и память остается выделенной до тех пор, пока программа больше не будет содержать ссылок на этот объект.
Когда не остаётся ссылок, объект считается больше ненужным, и занимаемая им память может быть освобождена. Нет явной необходимости уничтожать объект, потому что Java Освобождение памяти происходит автоматически через сборщик мусора.
Техника, лежащая в основе этого, известна как Вывоз мусораПрограммы, которые не освобождают память, в конечном итоге аварийно завершают работу, когда больше нечего выделять. Такие программы называются программами с ошибками. утечки памяти. Сбор мусора в Java запускается автоматически На протяжении всего срока действия программы, что снимает необходимость в ручном распределении ресурсов и снижает риск утечек.
В языке C, напротив, программист отвечает за освобождение памяти, динамически выделенной с помощью функции free(). Именно здесь и возникает проблема. Java Управление памятью дает существенное преимущество.
Современные JVM HotSpot поставляются с несколькими сборщиками мусора, настроенными для различных рабочих нагрузок. Сборщик мусора G1 по умолчанию ориентирован на сбалансированную пропускную способность и время пауз на многогигабайтных кучах. ZGC и Shenandoah нацелены на паузы менее миллисекунды на очень больших кучах, что делает их наиболее эффективными.tracЭто особенно важно для сервисов, чувствительных к задержкам. Выбор правильного сборщика и настройка размеров молодого поколения, старого поколения и метапространства — ключевой навык для этого. Java перформансная работа.
Примечание: Все объекты создаются в разделе памяти «Куча», который находится под управлением сборщика мусора.
Пример: изучить механизм сборщика мусора в Java
В этом пошаговом руководстве показано, когда ссылки становятся доступными для сборки мусора внутри простой программы.
Шаг 1) Скопируйте следующий код в редактор.
class Student{ int a; int b; public void setData(int c,int d){ a=c; b=d; } public void showData(){ System.out.println("Value of a = "+a); System.out.println("Value of b = "+b); } public static void main(String args[]){ Student s1 = new Student(); Student s2 = new Student(); s1.setData(1,2); s2.setData(3,4); s1.showData(); s2.showData(); //Student s3; //s3=s2; //s3.showData(); //s2=null; //s3.showData(); //s3=null; //s3.showData(); } }
Шаг 2) Сохраните, скомпилируйте и запустите код. Как показано на диаграмме, создаются два объекта и две переменные-ссылки.
Шаг 3) Раскомментируйте строки 20, 21 и 22. Сохраните, скомпилируйте и запустите код.
Шаг 4) Как показано на диаграмме ниже, теперь две переменные-ссылки указывают на один и тот же объект.
Шаг 5) Раскомментируйте строки 23 и 24. Сохраните, скомпилируйте и запустите код.
Шаг 6) Как показано ниже, s2 становится равным null, но s3 по-прежнему указывает на объект, поэтому объект еще не подлежит сборке мусора.
Шаг 7) Раскомментируйте строки 25 и 26. Сохраните, скомпилируйте и запустите код.
Шаг 8) На данном этапе никакие ссылки не указывают на объект, поэтому он становится доступным для сборки мусора. Сборщик мусора удаляет его из памяти, и восстановить его невозможно.
Как удалить объект в Java?
Java В системе отсутствует оператор ручного удаления, поэтому стандартный подход заключается в удалении всех ссылок на объект, чтобы сборщик мусора мог его освободить.
1) Чтобы объект стал доступен для сборки мусора, присвойте значение null каждой переменной-ссылке, указывающей на него.
2) Примитивные типы не являются объектами, поэтому им нельзя присвоить значение null. Их память автоматически освобождается при удалении фрейма из окружающего стека.


















