Стек может быть сборщиком мусора. Однако в большинстве реализаций 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, описанное выше.