Насколько я понимаю, в Java стековая память содержит примитивы и вызовы методов, а кучевая память используется для хранения объектов.
Предположим, у меня есть класс
class A {
int a ;
String b;
//getters and setters
}
Где будет храниться примитив
a
в классеA
?Почему куча памяти вообще существует? Почему мы не можем хранить все в стеке?
Когда объект получает мусор, уничтожается ли стек, связанный с возражаемым?
Ответы:
Основное различие между стеком и кучей - это жизненный цикл значений.
Значения стека существуют только в пределах функции, в которой они созданы. Как только она возвращается, они отбрасываются.
Однако значения кучи существуют в куче. Они создаются в определенный момент времени и уничтожаются в другой (GC или вручную, в зависимости от языка / времени выполнения).
Теперь Java хранит только примитивы в стеке. Это уменьшает размер стека и помогает сохранить размеры отдельных стековых фреймов, что позволяет использовать больше вложенных вызовов.
Объекты создаются в куче, и в стеке передаются только ссылки (которые, в свою очередь, являются примитивами).
Поэтому, если вы создаете объект, он помещается в кучу со всеми переменными, которые ему принадлежат, так что он может сохраняться после возврата вызова функции.
источник
char
числа являются числами и могут использоваться взаимозаменяемо как таковые. Ссылки также являются просто числами, относящимися к адресу памяти, длиной 32 или 64 бита (хотя они не могут использоваться как таковые - если вы не возитесьsun.misc.Unsafe
).boolean
,byte
,short
,char
,int
,long
,float
Иdouble
.)Где хранятся примитивные поля?
Примитивные поля хранятся как часть объекта, который где-то создается . Самый простой способ подумать, где это - это куча. Однако это не всегда так. Как описано в теории и практике Java: городские легенды производительности, вновь :
Таким образом, помимо высказывания «объект создан, и поле там тоже», нельзя сказать, находится ли что-то в куче или в стеке. Обратите внимание, что для небольших короткоживущих объектов возможно, что «объект» не будет существовать в памяти как таковой, и вместо этого его поля могут быть помещены непосредственно в регистры.
Статья заканчивается:
Таким образом, если у вас есть код, который выглядит так:
где
...
не позволяетqux
покинуть эту область, вместо этогоqux
может быть размещен в стеке. Это на самом деле выигрыш для виртуальной машины, потому что это означает, что ей не нужно собирать мусор - он исчезнет, когда покинет область видимости.Подробнее об анализе побега в Википедии. Для тех, кто хочет вникать в статьи, Escape Analysis for Java от IBM. Для тех, кто пришёл из мира C #, вы можете найти хорошие чтения Эрика Липперта «Стоп - это деталь реализации» и «Правда о типах значений» (они полезны для типов Java, так как многие концепции и аспекты одинаковы или похожи) , Почему в книгах .Net говорится о распределении стека и кучи памяти? и идет в это.
По стэку и куче
В кучу
Итак, зачем вообще стек или куча? Для вещей, которые выходят за рамки, стек может быть дорогим. Рассмотрим код:
Параметры тоже являются частью стека. В ситуации, когда у вас нет кучи, вы будете передавать полный набор значений в стеке. Это хорошо для
"foo"
небольших строк ... но что произойдет, если кто-то поместит в эту строку огромный XML-файл. Каждый вызов будет копировать всю огромную строку в стек - и это будет довольно расточительно.Вместо этого лучше поместить объекты, у которых есть некоторая жизнь, за пределы непосредственной области видимости (переданные в другую область видимости, застрявшие в структуре, которую поддерживает другой человек и т. Д.) В другую область, которая называется кучей.
В стеке
Вам не нужен стек. Можно гипотетически написать язык, который не использует стек (произвольной глубины). Старый бейсик, на котором я учился в юности, делал так: можно было делать только 8 уровней
gosub
вызовов, и все переменные были глобальными - стека не было.Преимущество стека состоит в том, что когда у вас есть переменная, которая существует с областью действия, когда вы покидаете эту область, этот кадр стека выталкивается. Это действительно упрощает то, что есть, а что нет. Программа переходит к другой процедуре, новому стековому фрейму; программа вернется к процедуре, и вы вернетесь к той, которая видит вашу текущую область; программа покидает процедуру, и все элементы в стеке освобождаются.
Это действительно облегчает жизнь человеку, пишущему среду выполнения кода, для использования стека и кучи. В них просто много концепций и способов работы с кодом, позволяющих человеку, пишущему код на языке, быть полностью свободным от мысли о них.
Природа стека также означает, что он не может стать фрагментированным. Фрагментация памяти - реальная проблема с кучей. Вы выделяете несколько объектов, затем мусор собираете средний, а затем пытаетесь найти место для следующего большого, который будет выделен. Это беспорядок. Возможность поместить вещи в стек вместо этого означает, что вам не нужно иметь с этим дело.
Когда что-то собирается
Когда что-то собирает мусор, его уже нет. Но это только сборщик мусора, потому что о нем уже забыли - в программе больше нет ссылок на объект, к которым можно получить доступ из текущего состояния программы.
Я укажу, что это очень большое упрощение сборки мусора. Существует много сборщиков мусора (даже в Java - вы можете настроить сборщик мусора, используя различные флаги ( документы ). Они ведут себя по-разному, и нюансы того, как каждый из них делает что-то, слишком глубоки для этого ответа. Вы можете прочитать Основы сборки мусора Java, чтобы лучше понять, как это работает.
Тем не менее, если что-то размещено в стеке, оно не является сборщиком мусора как часть
System.gc()
- оно освобождается, когда всплывает кадр стека. Если что-то находится в куче и ссылается на что-либо в стеке, это не будет сборкой мусора в это время.Почему это важно?
По большей части, это традиция. Написанные учебники, классы компиляторов и документация по различным битам имеют большое значение для кучи и стека.
Однако современные виртуальные машины (JVM и аналогичные) приложили много усилий, чтобы скрыть это от программиста. Если вам не хватает одного или другого и вам нужно знать почему (вместо того, чтобы просто увеличивать объем памяти), это не имеет большого значения.
Объект находится где-то и находится там, где к нему можно правильно и быстро получить доступ в течение соответствующего промежутка времени, в течение которого он существует. Если это в стеке или куче - это не имеет значения.
источник
источник
В куче, если только Java не выделяет экземпляр класса в стеке в качестве оптимизации после подтверждения с помощью escape-анализа, что это не повлияет на семантику. Однако это деталь реализации, поэтому для всех практических целей, кроме микрооптимизации, ответ «в куче».
Память стека должна быть выделена и освобождена последней в порядке очереди. Память кучи может быть выделена и освобождена в любом порядке.
Когда объект собирается мусором, больше нет ссылок, указывающих на него из стека. Если бы они были, они бы сохранили объект. Примитивы стека вообще не собираются мусором, потому что они автоматически уничтожаются при возврате функции.
источник
Стековая память используется для хранения локальных переменных и вызова функций.
Пока куча памяти используется для хранения объектов в Java. Неважно, где объект создается в коде.
В этом случае примитив a связан с объектом класса A. Так оно и создается в куче памяти.
Сборщик мусора работает в объеме памяти кучи, поэтому он уничтожает объекты, не имеющие цепочки ссылок, от корня до корня.
источник
Для лучшего понимания (память кучи / стека):
источник