digital-garden/knowledge/dev/java/gc/Generational Collection.md

5.4 KiB
Raw Blame History

aliases tags date zero-link parents linked
зрелость/🌱
2023-11-07
../../../../garden/ru/meta/zero/00 Java разработка
../../../../garden/ru/dev/java/gc/Garbage Collector

Этот алгоритм основан на нескольких идеях.

  • Слабая гипотеза о поколениях: Большинство объектов временные.
  • Сильная гипотеза о поколениях: Чем старше объект, тем дольше он проживет.
    • Поведение кешей с политикой Least Recently Used ей прямо противоречит
  • Чем объект больше, тем больше шансов, что он нам будет нужен дольше по времени.
  • Старые объекты редко ссылаются на молодые.

Поэтому куча часто делится на два "поколения" - молодое и старое. А сборщик мусора может использовать различные подходы для сборки в поколениях.

  • Young Generation. Здесь хранятся молодые объекты.
    • Eden Space. Здесь выделяется память по новые объекты.
    • Survivor Space. Сюда переносятся объекты, которые пережили несколько сборок мусора.
  • Old Generation. Здесь хранятся долгоживущие объекты.
    • Сборка мусора происходит реже
  • MetaSpace
    • Сборка мусора здесь не производится
    • С java 8 называется MetaSpace, раньше называлось Pemanent Generation.

В общем случае новые объекты создаются в Eden, после чего какое-то время они находятся там. Если объекты пережили N сборок мусора, то сборщик мусора может принять решение о переносе объекта в Old Generation. Производительность сборки мусора в Young Generation напрямую зависит от количества живых объектов.

Конкретно в Hotspot, если объект большой (1+ mb) он может быть сразу помещен в Old Generation. А новые объекты создаются в области eden, если объект переживает сборку мусора, то он переносится в область s0, если переживает сборку в s0, переносится в s1, после чего переносится в Old Generation.

Если eden заполнен, то выполняется minor сборка мусора.

При сборке только в молодом поколении есть проблема: мы можем удалить объект в молодом поколении, на который ссылаются из старого поколения. В Serial GC/Parallel GC для решения этой проблемы используют специальную структуру Card Table. При записи ссылки из старого поколения в молодое, в Card Table делается пометка. Эта пометка означает, что в такой-то области старого поколения может быть ссылка на молодое. То есть это не точное знание, а маркер, который говорит нам проверить какую-то область памяти на наличие ссылок.

В G1 происходит примерно то же самое, но там помимо Card Table есть также Remembered Set. Remembered Set асинхронно строится по Card Table. Это позволяет нам собирать регионы отдельно.

Однако это привело к большом оверхеду по памяти для хранения этого Remembered Set. И с каких-то версий G1 стал более похожим на традиционные сборщики: ссылки между молодыми поколениями перестали хранится, но из-за этого мы должны собирать сразу все молодое поколение, мы больше не можем собирать только часть молодого поколения.

В Shenandoah GC вместо Card Table решили использовать Matrix. Это грубый Card Table, но для каждого региона. Размер Matrix зависит от количества регионов.