Search
Write a publication
Pull to refresh

Comments 20

Мне кажется, что показывая график из статьи 2013 года стоило бы особо подчеркнуть, что данные могут быть неактуальны. Особенно для графика пауз GC.
На графике в общем-то указана версия Java на которой производились тесты, но я все таки добавил еще одно упоминание о том, что статья старая
Проясните пожалуйста вопрос — как происходит адресация. В С++ например ссылка на данные прямая — тупо хранится адрес и по нему программа ходит за данными. А в джаве, данные объекта перемещаются в памяти, и значит нужно каждый раз вычислять этот адрес при каждом обращении к объекту.
Не уверен, что понял вопрос. Что значит данные объекта перемещаются в памяти? У нас есть объект в памяти, на него есть ссылка, это по факту адрес объекта.
Если вам интересно как происходит процесс сжатия/расжатия, вот, для примера, код JVM (из файла compressedOops.inline.hpp) который делает декодирование адреса.
  inline oop decode_not_null(narrowOop v) {
    assert(!is_null(v), "narrow oop value can never be zero");
    address base = Universe::narrow_oop_base();
    int    shift = Universe::narrow_oop_shift();
    oop result = (oop)(void*)((uintptr_t)base + ((uintptr_t)v << shift));
    assert(check_obj_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
    return result;
  }

Сборщик мусора может перемещать объекты. Там есть несколько областей памяти, которые соответствуют короткоживущим и долгоживущим объектам. Если данные переместились, то адрес сменился. То есть логически поразмыслив понятно, что — адрес или надо вычислять каждый раз или менять все ссылки на этот блок после каждой сборки мусора. Вот хотел бы понять, как это происходит
Да, я кажется понял, вы спрашиваете «Что происходит со ссылками когда GC перемещает объект?». Кажется вот здесь описан механизм перемещения объектов в JVM GC:
Specifically, the GC walks the graph of reachable objects within the «from» space, starting from each of the GC roots. Each time it finds a reference to a node (in an instance field, static field, stack frame, etc), it checks the object that the reference points to to see if it has been marked as visited.

* If it is not yet marked, the GC does the following:

It marks the object in the from-space.
It copies the object into the to-space.
It stores the address of the object in to space in the from-space object. (This is like a forwarding address.)
It recursively visits each reference field of the to-space copy of the object.
The result of this the reference to the to-space object.

* If the object has been marked already, the GC looks up the forwarding address, and returns that.
Вот и вопрос — как адресуются данные при таком раскладе. Что происходит, когда надо достать object.field? В С++ просто лезет по адресу в память и получает данные. А как в джаве, если адрес плавает?

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

Там по-моему немножко не так делается, из-под потоков, которые нужно остановить, "выдергиваются" страницы памяти (размапливаются) и gc делает в них все что ему требуется, двигает объекты, правит адреса, и так далее, а потоки останавливаются сами по page fault exception, потом jvm мапит все обратно и потоки продолжают работать как ни в чем не бывало.

A это вроде как только в режиме ядра можно делать — ring0. И страницы по 4кб занимают. Что на каждый объект по 4кб резервируется?

Вот тут подробное описание. Страница для page fault создается одна на поток, а не на объект. Хандлеры на page fault можно регистрировать и в user space, все современные ядра ос позволяют это.

тема интересная, но надо разбираться.
у меня тоже бродили мысли, что устройство виртуальной памяти очень подходит для сбора мусора, если мусорщику дать возможность манипулировать такими вещами, как dirty bit, page fault, tlb и тп
Вот как раз тут у меня куча вопросов — неужели вся куча перемалывается? Я могу создать 100500 объектов, которые друг на друга ссылаются.
Все адреса хранятся в куче. Если просто пройтись по памяти и заменить байты на новые, то можно зацепить простые данные. Отсюда следует
, что надо как-то разделять простые данные и адреса объектов. Вот интересно, как это сделано и как происходит адресация данных.

PS Все больше ощущаю, что джава программисты не понимают вопросов, которые исходят от программистов С/С++. В понимании С виртуальная память представляет собой простой большой линейный массив и в нем нет регионов, которые декларируются в джаве. А любое разделение сопровождается доп расходами и необходимостью хранить адреса разделов и как-то постоянно складывать базу и смещение чтобы вычислить реальный адрес
вот как gc детектит, ссылка это или примитив:
stackoverflow.com/a/12097214/1961500

И вот, как устроен OopMap:
stackoverflow.com/a/26049445/1961500

Т.е. по сути для интерпретируемого кода, проверяет выравнивание объекта и установленный бит признака объекта, а для нативного кода, сгенеренного jit — при компиляции по инструкциям сохраняет смещения ссылок в стеке рядом с скомпиленным методом.
В джаве нет работы напрямую с адресами в памяти. Вопросы с адресом field, измененным в результате работы GarbageCollector, JVM инкапсулирует.
В самом языке нет, но в конечном счете все работает через ассемблер. Вот и интересно какова стоимость хозяйства по сравнению с прямым доступом к памяти.
Sign up to leave a comment.

Articles