Собирается ли мусор в стеке на Java? - PullRequest
53 голосов
/ 15 марта 2010

Память кучи - это сборщик мусора в Java.

Собирается ли мусор в стеке?

Как восстанавливается память стека?

Ответы [ 9 ]

36 голосов
/ 15 марта 2010

Память в стеке содержит параметры метода и локальные переменные (если быть точным: ссылки на объекты и сами переменные для примитивных типов). Это будет автоматически удалено, если вы выйдете из метода. Если переменные являются ссылками (на объекты), то сами объекты находятся в куче и обрабатываются сборщиком мусора.

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

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

28 голосов
/ 15 марта 2010

Стек не является сборщиком мусора в Java.

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

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

14 голосов
/ 16 марта 2010

Стек может быть сборщиком мусора. Однако в большинстве реализаций JVM он обрабатывается как «стек», который по определению исключает сборку мусора.

То, что мы называем стеком, - это накопление контекстов активации метода : для каждого вызванного метода это концептуальная структура, которая содержит аргументы метода, локальные переменные, скрытый указатель на контекст для вызова метод и слот для сохранения указателя инструкций. Контекст активации недоступен как таковой из самого языка Java. Контекст становится бесполезным при выходе из метода (с return или из-за вызванного исключения). Случается, что когда метод A вызывает метод B, гарантируется, что когда A восстановит контроль, контекст для B станет бесполезным. Это подразумевает, что время жизни контекста для B является поддиапазоном времени жизни контекста для A. Следовательно, контексты активации (для данного потока) могут быть распределены с помощью дисциплины LIFO («Last In, First Out»). Проще говоря, стек: новый контекст активации помещается поверх стека контекстов, и контекст сверху будет удаляться первым.

На практике контексты активации (также называемые кадры стека ) объединяются в порядке стека в выделенной области. Эта область получается из операционной системы, когда поток запускается, и операционная система возвращает ее, когда поток завершается. Вершина стека обозначается специальным указателем, который часто содержится в регистре процессора (это зависит от того, интерпретирует ли JVM или компилирует код). «Указатель на контекст вызывающего» является виртуальным; контекст вызывающей стороны обязательно расположен чуть ниже в порядке стека. GC не вмешивается: область для стека создается и восстанавливается синхронно из самой активности потока. Это также, как это работает во многих языках, таких как C , которые вообще не имеют GC.

Теперь ничто не мешает реализации JVM делать иначе, например, выделение контекстов активации в куче и сбор их GC. Обычно это не делается в виртуальных машинах Java, поскольку выделение стека происходит быстрее. Но некоторые другие языки должны делать такие вещи, особенно те, которые играют с продолжениями , все еще используя GC (например, Scheme и его функция call-with-current-continuation) потому что такие игры нарушают правило LIFO, описанное выше.

8 голосов
/ 15 марта 2010

Часть стека памяти работает так же, как «стек». Я знаю, это звучит плохо, но это именно то, как это работает. Данные добавляются сверху, друг над другом (pushed onto the stack) и автоматически удаляются сверху (popped off the stack) при запуске вашей программы. Это не сборщик мусора - и это не нужно, так как эта память автоматически восстанавливается после извлечения данных из стека. И когда я говорю «reclamed», я не имею в виду, что он перераспределяется - просто место в памяти стека, где будут храниться следующие данные, уменьшается по мере удаления.

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

Но суть в том, что память стека используется и восстанавливается, когда функции входят и выходят из области видимости - автоматически. Таким образом, в конце выполнения вашей программы вся память стека будет освобождена и затем возвращена обратно в операционную систему.

4 голосов
/ 18 марта 2010

Если вы обращаетесь к памяти, используемой в стеке, это не сборщик мусора.
Виртуальная машина Java использует явные инструкции байт-кода для резервирования и освобождения памяти в стеке, эти инструкции генерируются компилятором и управляют временем жизни примитивов, таких как int, boolean, double и объектных ссылок в стеке.
Были планы реализовать так называемую хвостовую оптимизацию, которая удаляла бы некоторые записи из стека, когда стало известно, что они больше не используются, но я не знаю ни одного jvm, который уже поддерживает это.
Так что нет никакой сборки мусора для самого стека, только компилятор сгенерировал команды push и pop для управления использованием памяти.

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

1 голос
/ 15 марта 2010

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

1 голос
/ 15 марта 2010

Все объекты в Java расположены в куче. (По крайней мере, что касается спецификации, фактическая реализация может разместить их в стеке, если они прозрачно ведут себя так, как будто они находятся в куче.)

То, что является предметом коллекционирования, немного неуловимо. Если единственная ссылка на объект находится в одном кадре стека, и можно показать, что ссылка больше не будет использоваться, тогда объект может быть собран. Если объект используется только для чтения поля, то чтение этого поля может быть оптимизировано вперед, и объект будет собран раньше, чем вы ожидаете.

Обычно это не имеет значения, если вы не используете финализаторы (или предположительно Reference с). В этом случае вы должны быть осторожны и использовать блокировки / volatile для обеспечения отношения happens-before.

Когда потоки останавливаются, обычно весь стек освобождается.

0 голосов
/ 23 февраля 2016

Нет. Стек не является мусором, собранным в Java. Каждый поток имеет свой собственный стек и содержит:

  1. Значения, специфичные для метода (кратковременные) и
  2. Ссылки на объекты, созданные в куче и на которые ссылается метод

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

Следовательно, данные в стеке автоматически очищаются, когда метод / программа выходит из области видимости.

0 голосов
/ 15 марта 2010

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

...