Сборка мусора — корневые узлы

Недавно я прочитал отрывки о сборке мусора (в основном на Java), и один вопрос до сих пор остается без ответа: как JVM (или система времени выполнения в целом) отслеживает ТЕКУЩИЕ живые объекты?

Я понимаю, что объекты - это те, которые в данный момент находятся в стеке, поэтому все локальные переменные или параметры функций, которые ЯВЛЯЮТСЯ объектами. Проблема с этим подходом заключается в том, что всякий раз, когда система времени выполнения проверяет, что в данный момент находится в стеке, как она будет отличать ссылочную переменную от простого int? не может, не так ли?

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


person Bober02    schedule 12.12.2011    source источник


Ответы (3)


Я обнаружил, что ответ, предоставленный greyfairer, неверен. Среда выполнения JVM не собирает корневой набор из стека, просматривая, какие байт-коды используются для передачи данных в стек. Фрейм стека состоит из 4-байтовых (32-битных) слотов. Каждый слот может быть ссылкой на объект кучи или примитивное значение, такое как int. Когда требуется GC, среда выполнения сканирует стек сверху вниз. Для каждого слота он содержит ссылку, если:

а. Он выровнен по границе 4 байта.

б. Значение в слоте указывает на область кучи (между нижней и верхней границей).

в. Аллокбит установлен. Аллокбит — это флаг, указывающий, выделена ли соответствующая ему ячейка памяти или нет.

Вот моя ссылка: http://www.ibm.com/developerworks/ibm/library/i-garbage2/.

Есть и другие методы поиска корневого набора (не в Java). Например, поскольку указатели обычно выравниваются по границе 4/8 байтов, первый бит может использоваться для указания того, является ли слот примитивным значением или указателем: для примитивных значений первый бит устанавливается равным 1. Недостатком этого является что у вас есть только 31 бит (32-битная арка) для представления целого числа, и все операции над примитивными значениями включают сдвиг, что является очевидным накладным расходом.

Кроме того, вы можете выделить все типы, включая int, в куче. То есть все вещи являются объектами. Тогда все слоты в кадре стека являются ссылками.

person Rainfield    schedule 23.08.2012
comment
Так что в целом это довольно низкоуровневая дифференциация, а не JVM? Но в JVM для байт-кода объявлен тип Reference, так почему бы его не использовать? Вы уверены, что именно на таком низком уровне, а не на уровне байт-кода? - person Bober02; 23.08.2012
comment
Насколько я знаю (основываясь как на ссылке, которую я дал ранее, так и на просмотре кодов нескольких реализаций JVM), я уверен, что мое понимание правильное. Вы можете просто погрузиться в коды GC некоторых реализаций JVM с открытым исходным кодом, чтобы проверить это. Им всем нужно пройтись по стеку, чтобы узнать ссылку. Однако, возможно, критерии, используемые для проверки того, является ли слот эталонным или нет, немного отличаются (большинство из них проверяют a. и b. Для c это действительно основано на реализации). - person Rainfield; 24.08.2012
comment
Почему бы не использовать байт-код, это мое понимание (не уверен, правильно это или нет). Сборщик мусора работает во время выполнения, но байт-код генерируется во время компиляции и является статическим. Когда происходит GC, системе выполнения необходимо найти корни и следовать им, чтобы найти живые объекты. . Чтобы сделать это, вы должны фактически проверить значение в каждом слоте кадра стека, даже если вы знаете, что этот слот содержит ссылку во время компиляции (как сказал greyfairer, вы знаете это, глядя на байт-код). Потому что вам нужно знать точное значение ссылки, чтобы найти другие объекты в куче. - person Rainfield; 24.08.2012
comment
Так зачем вообще проверять байт-код? Вы все равно должны пройтись по стеку. - person Rainfield; 24.08.2012
comment
Где находится аллокбит? Находясь где-то за пределами объекта, вы увеличиваете накладные расходы на выделение (всего на одну операцию, но это значительно). Находясь внутри объекта, вы можете неправильно интерпретировать другие данные как аллокбит и столкнуться с проблемами, упомянутыми в нижней части этой статьи. - person maaartinus; 15.09.2018
comment
@maaartinus ну, эта ныне мертвая ссылка наверняка описывала JVM от IBM, если она вообще была о Java. Поскольку мы уже знаем, что он никогда не применялся к JVM HotSpot, остается единственный вопрос, применим ли он по-прежнему к JVM IBM. Именно такой ответ мы получаем, когда спрашиваем, что делает «Java», когда на самом деле речь идет о конкретном поведении реализации JVM. - person Holger; 17.09.2018

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

Например, если функция f1 вызывает функцию f2(int i, Object o, long l), вызывающая функция f1 поместит 4 байта в стек (или в регистр), представляющие i, 4 (или 8?) байтов для ссылка на o и 8 байтов на l. Вызванная функция f2 знает, где найти эти байты в стеке, и потенциально может скопировать ссылку на какой-либо объект в куче или нет. Когда функция f2 вернется, вызывающая функция удалит параметры из стека.

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

Согласно http://www.javacoffeebreak.com/articles/thinkinginjava/abitaboutgarbagecollection.html, java использует отслеживающий сборщик мусора, а не алгоритм подсчета ссылок .

person GreyFairer    schedule 12.12.2011
comment
Спасибо за ваш ответ. Имея это в виду, как происходит сборка мусора, когда она инициируется JVM? как он на самом деле находит корневые узлы - прыгает обратно в стек или у него есть отдельная коллекция узлов? - person Bober02; 13.12.2011
comment
См. Ссылку на статью для углубленного анализа. - person GreyFairer; 13.12.2011
comment
Я нашел следующее предложение в статье, на которую вы ссылались: «Отметить и развернуть следует той же логике, начиная со стека и статического хранилища и отслеживая все дескрипторы для поиска живых объектов». Что это за мистические ручки, к которым они относятся... - person Bober02; 14.12.2011
comment
Ручки, указатели, ссылки, мне все равно. Это означает, что среда выполнения действительно хранит список местоположений в стеке, которые являются ссылками/указателями на объекты в куче, и оттуда она находит указатели на другие объекты, на которые ссылаются эти объекты, и так далее... - person GreyFairer; 15.12.2011
comment
Ах, хорошо, тогда используется вспомогательная структура данных... Это имеет смысл! - person Bober02; 17.12.2011
comment
То, что делает интерпретатор, совершенно не имеет значения, поскольку значительные части кода компилируются в машинный язык. Так что ваше решение, поскольку оно не решает проблему. - person maaartinus; 15.09.2018

HotSpot VM создает карту GC для каждой скомпилированной подпрограммы, которая содержит информацию о том, где находятся корни. Например, предположим, что он скомпилировал подпрограмму в машинный код (принцип тот же для байтового кода) длиной 120 байт, тогда карта GC для нее может выглядеть примерно так:

0 : [RAX, RBX]
4 : [RAX, [RSP+0]]
10 : [RBX, RSI, [RSP+0]]
...
120 : [[RSP+0],[RSP+8]]

Здесь [RSP+x] должно указывать расположение стека и R?? регистров. Таким образом, если поток останавливается на инструкции сборки по смещению 10 и выполняется цикл gc, то HotSpot знает, что три корня находятся в RBX, RSI и [RSP+0]. Он отслеживает эти корни и обновляет указатели, если ему нужно переместить объекты.

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

person Björn Lindqvist    schedule 11.09.2016
comment
Эта карта нужна только в безопасных точках, а не на произвольных смещениях (что может быть причиной ваших промежутков между 0, 4 и 10). Я только что нашел эту статью подтверждая ваш ответ. - person maaartinus; 15.09.2018