Области памяти Java и сборщик мусора

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

Первое, чего я не понял, это то, что сборщик мусора начинается с корней gc и перемещается по графу для обнаружения живых экземпляров, но как он узнает, какой объект молодой, а какой старый? Как узнать, в какой области памяти находится объект?

Во-вторых, если мы выполняем только незначительную коллекцию, как gc узнает, не ссылается ли объект в молодом поколении объектами в старом поколении или статической ссылкой из области метода?

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

Спасибо!


person alobodzk    schedule 25.09.2014    source источник


Ответы (3)


YoungGen / OldGen и PermGen - это три области, в которых находится Java Heap. JVM хорошо разбирается в границах каждого из них.

  1. При сборе мусора GC сначала решает, в каком пространстве запускать, а затем определяет корни GC каждого объекта в этом пространстве. Является ли объект молодым или старым, определяется пространством, в котором он находится в куче. Сборщик мусора поддерживает состояние каждого объекта, например, сколько циклов сборки мусора пережил каждый объект, что дает сборщику мусора оценку того, подходит ли время для перемещения объекта из молодого в старый.

  2. Граф объектов решает, ссылается ли объект молодого поколения на ссылку старого поколения.

  3. Если объект уплотнен, ссылка также обновляется. Это также происходит, когда Объекты перемещаются из Молодого в Старое поколение.

person Geek    schedule 25.09.2014
comment
Спасибо @Geek! И еще кое-что: как сборщик мусора выполняет второстепенную сборку? Это также связано с выбором корней GC? Я понимаю, что в второстепенной коллекции вы не хотите трогать те, что в старом поколении, так как же GC может решить, какие корни GC следует обрабатывать в второстепенной коллекции? - person alobodzk; 30.09.2014

Ответ зависит от алгоритма GC, поэтому вы найдете некоторые варианты ответов.

как сборщик мусора узнает, какой объект молодой, а какой старый? Как узнать, в какой области памяти находится объект?

Адрес в памяти объекта ответит, так как каждая область имеет тенденцию фиксироваться в местоположении. Изменение размера возможно, но это произойдет только тогда, когда JVM приостановила все рабочие потоки. Помните также, что у сборщика G1 нет поколений, поэтому ответ зависит от используемого алгоритма.

Как gc узнает, что на объект в молодом поколении не ссылаются объекты в старом поколении или статическая ссылка из области метода?

Некоторые алгоритмы сборки мусора выполняют полную проверку всех объектов в куче. Другие полагаются на наблюдение, что количество ссылок, переходящих от старого поколения к молодому, относительно невелико, поэтому JVM отслеживает их и использует в качестве корней для целей маркировки. Механизмом для этого обычно является система оценочных карточек, и это причина того, почему некоторые алгоритмы GC, имеющие очень большое пространство предков, могут замедлять GC молодого пространства. Потому что каждую карточку для каждого объекта нужно проверять, чтобы увидеть, может ли он иметь указатель на молодого поколения.

Последнее, что после разметки и зачистки иногда делают уплотнение. Как gc узнает, какие ссылки на перемещенные объекты необходимо обновить?

Опять же, ответ действительно меняется, поскольку JVM могут изменять эти детали. В некоторых алгоритмах используется двойная косвенная адресация, поэтому указатели очень легко найти и обновить. Это предполагает хранение большого индекса для каждого объекта. Однако было показано, что это замедляет пользовательский код, когда сборщик мусора не работает, поскольку выполняющийся код должен постоянно искать, где на самом деле находился объект, поэтому да, некоторые алгоритмы сборщика мусора действительно отслеживают ссылки.

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

person Chris K    schedule 25.09.2014
comment
Спасибо, Крис! Могу я попросить вас проверить мой вопрос в комментариях к ответу компьютерщика? - person alobodzk; 30.09.2014
comment
@alobodzk, мы можем быть более конкретными, если выберем один алгоритм. Итак, давайте перейдем к CMS, реализации Oracle Hotspot Concurrent Mark and Sweep. Их молодой GC использует обычные корни, то есть потоки, нативные вызовы и так далее. Для части от старого поколения к молодому у них есть большой массив битов, который совпадает с каждым адресом памяти в старом поколении. Каждый бит говорит, что может быть указателем на молодой ген (но может быть ложным срабатыванием). Молодой ген сканирует это и пускает корни оттуда. Они называются «карточным столом». - person Chris K; 30.09.2014
comment
Некоторые полезные сведения о карточных столах можно прочитать здесь: Mechanical-sympathy.blogspot.co.uk/2013/07/ - person Chris K; 30.09.2014
comment
Спасибо! Вы упомянули CMS, но я видел видео на YouTube с парнем из Azul Systems на GC, и он сказал, что большинство jvms использует сбор копий в второстепенной коллекции, которая, предположительно, будет, если я правильно понимаю без фазы отметки, gc просто копирует живые объекты в новую область памяти, и я не понимаю, как это может работать, как вы можете определить, какие объекты молодые, не просматривая граф и не проверяя их ссылочные адреса? - person alobodzk; 30.09.2014
comment
@alobodzk нет отметки фазы? здесь нужно быть осторожным с терминологией. Сама CMS НЕ ЯВЛЯЕТСЯ молодым сборщиком пространства в JVM Oracle. Он опирается на традиционного молодого космического коллекционера STW (Stop The World). CMS имеет «фазу», которую он явно называет «фазой метки», и эта фаза метки является как параллельной, так и параллельной. Я подозреваю, что видео, которое вы смотрели, относилось к версии молодого поколения как к STW (то есть не параллельно с потоками приложений). Но это не значит, что молодой космический водоросль не ходит по куче, чтобы идентифицировать живые объекты. Совершенно верно. - person Chris K; 01.10.2014

  1. Каждый раз, когда GC проверяет, можно ли собрать объект, он увеличивает счетчик в объекте, который сообщает ему, сколько раз этот объект был посещен GC. Это самый простой способ узнать, когда объект необходимо передать от молодого поколения к постоянному поколению. Но что касается знания, в какой области находится объект, адрес объекта можно использовать для его вычисления. (Например, JVM просто скажет, что адреса памяти от 0 до 100 - это молодое поколение, а 101+ - это постоянное поколение.)
  2. Даже во время незначительной коллекции просматривается весь граф объектов для проверки ссылок. По крайней мере, теоретически так и происходит, на практике будут некоторые оптимизации. Но общая идея такова.
  3. Поскольку первым шагом является построение графа ссылок, эта информация все еще доступна на этапе уплотнения. Но да, уплотнение гигабайтных куч занимает много времени.
person biziclop    schedule 25.09.2014