«Сборка мусора Java — это процесс, с помощью которого Java-программы выполняют автоматическое управление памятью». JVM (виртуальная машина Java) может запускать Java-приложения, компилируя их в байт-код. Когда Java-программы выполняются на JVM, объекты создаются в куче, которая представляет собой часть памяти, выделенную для программы. Со временем некоторые объекты перестанут быть нужными. Чтобы освободить память, сборщик мусора обнаруживает и удаляет эти неиспользуемые объекты. Сбор мусора осуществляется потоком демона под названием Сборщик мусора.
Понимание необходимости сборки мусора:
В таких языках программирования, как C и C++, за уничтожение объектов отвечает программист. Если программист забудет уничтожить неиспользуемые объекты, это в конечном итоге приведет к утечкам памяти, и после определенного момента не останется доступной памяти для создания новых объектов, и приложение выйдет из строя с выходом. Ошибка нехватки памяти. В Java сбор мусора происходит автоматически в течение жизненного цикла программы за счет освобождения памяти и, следовательно, предотвращения утечек памяти. Реализация сборки мусора находится в JVM. Каждая JVM может реализовать свою версию сборки мусора.
Состояние объекта: мертвый или живой
Когда Java-программы выполняются на JVM, объекты создаются в куче. За время существования Java-приложения создаются и выпускаются новые объекты, и в любой момент времени куча памяти состоит из двух типов объектов: мертвых и живых. Живые объекты используются и на них ссылаются из приложения. Мертвые объекты больше не используются и на них не ссылаются нигде в приложении. Сборщик мусора обнаруживает эти объекты и удаляет их, чтобы освободить память. Объект не станет кандидатом на сбор мусора, пока все ссылки на него не будут удалены.
Давайте посмотрим, как освободить ссылку на объект, чтобы она была доступна для сборки мусора:
создание нулевой ссылки. Когда ссылочные переменные объекта изменяются на нулевые, он становится недоступным и делает его пригодным для сборки мусора.
переназначение ссылочной переменной: когда ссылочная переменная одного объекта переназначается другому объекту, на предыдущий объект больше не ссылаются, он недоступен и делает его пригодным для сборки мусора. В приведенном ниже примере: первый объект, на который ссылался st1, теперь имеет право на сбор мусора.
создание объекта внутри метода: когда метод вызывается и если внутри метода создаются объекты, эти объекты становятся недоступными после завершения выполнения метода, что делает его пригодным для сборки мусора. В приведенном ниже примере: после завершения выполнения метода() оба объекта имеют право на сбор мусора.
использование анонимного объекта. Идентификатор ссылки анонимного объекта не сохраняется, поэтому объект становится недоступным, что делает его пригодным для сборки мусора.
Сбор мусора состоит из 3 основных этапов (маркировка, очистка, компактирование).
Отметить: пометить объекты как живые. На этом этапе, проходя по графу объектов, GC идентифицирует все живые объекты в памяти. Объекты, доступные для GC, помечаются как живые, а недоступные объекты считаются пригодными для сбора мусора.
Очистка.Второй этап – очистка мертвых объектов. После идентификации живых и мертвых объектов GC освободит память, содержащую мертвые объекты.
Компактный. На этапе очистки удаленные мертвые объекты могут находиться не рядом друг с другом, что может привести к фрагментации памяти. Этот этап обеспечивает расположение объектов в смежные блоки в начале кучи.
Ниже приведена иллюстрация того, как GC выполняет Mark, Sweep и Compact.
Несколько анализов показали, что большинство объектов недолговечны, а частые следы и компактные шаги для всех объектов в куче будут неэффективными и отнимающими много времени. Чтобы решить эту проблему, сборщики мусора Java реализуют стратегию сборки мусора поколений, которая классифицирует объекты по возрасту.
Поколенная сборка мусора. Существует три различных классификации объектов по сборщикам мусора. Молодое поколение, старое поколение и постоянное поколение.
Молодое поколение:Все вновь создаваемые объекты начинаются с молодого поколения, которое подразделяется на пространство Эдема (где начинаются все новые объекты) и два пространства выживания (S0 -FromSpace, S1 -ToSpace) (где объекты перемещаются из пространства Эдема после выживания в одном цикле сборки мусора). Когда объекты собираются из молодого поколения, это второстепенное событие сборки мусора.
поток объектов у молодого поколения:
- Сначала объекты распределяются в пространстве Эдема, при этом оба пространства выживания пустуют.
- JVM выполняет второстепенный сборщик мусора, когда пространство Эдема заполняется объектами (живыми или мертвыми). После удаления мертвых объектов все живые объекты теперь перемещаются из пространства Эдема в S0. Теперь Иден и S1 пусты.
- Когда пространство Эдема снова заполняется объектами, выполняется еще один второстепенный сборщик мусора и удаляются все мертвые объекты. На этот раз живые объекты из пространства Эдема и S0 перемещаются в S1. Теперь Иден и S0 пусты. В любой момент времени одно из мест выживших пусто.
- Когда выжившие объекты достигают определенного порога перемещения по пространству выживших, они перемещаются в Старое поколение.
Старое поколение: В конечном итоге сборщик мусора перемещает долгоживущие объекты из молодого поколения в старое поколение. Когда объекты старого поколения собираются мусором, это серьезное событие сбора мусора. Полная уборка мусора очищает как молодое, так и старое поколение.
Постоянная генерация: JVM хранит метаданные, такие как классы и методы, в постоянной генерации. Начиная с Java8, пространство памяти MetaSpace заменило пространство PermGen. Реализация отличается от реализации PermGen, поскольку размер кучи теперь изменяется автоматически. Это позволяет избежать проблемы нехватки памяти приложениями из-за ограниченного размера пространства кучи PermGen. MetaSpace может быть очищен от мусора, а классы, которые больше не используются, могут быть автоматически очищены, когда MetaSpace достигнет максимального размера.
Итак, теперь мы поняли, как работает сборщик мусора, давайте посмотрим на различные типы сборщиков мусора, доступные в JVM.
Последовательный сборщик мусора. Это базовый сборщик мусора, предназначенный для небольших приложений, работающих в однопоточной среде. Когда это запускается, это приводит к событию «остановить мир», когда все приложение приостанавливается.
Параллельный сборщик мусора: поток, который выполняет сборщик мусора одновременно с выполнением приложения. В параллельном сборщике несколько потоков используются для незначительной сборки мусора в молодом поколении, а один поток используется для основной сборки мусора в старом поколении. Запуск Parallel GC также вызывает событие «остановки мира». Поскольку он подходит для многопоточной среды, его можно использовать, когда необходимо выполнить большой объем работы и допустимы длинные паузы.
Параллельная очистка пометок (CMS GC):В CMS GC несколько потоков используются для второстепенной и основной сборки мусора. CMS работает одновременно с процессами приложений, чтобы свести к минимуму события остановки мира. В результате CMS использует больше ресурсов ЦП, чем другие GC. Итак, если вы можете выделить больше ЦП для повышения производительности, тогда CMS — лучший выбор, чем Parallel GC.
Garbage First (G1 GC):Это сборщик мусора по умолчанию, выбранный Java. G1 GC был задуман как замена CMS GC и был разработан для многопоточных приложений, которым доступен больший размер кучи. Он параллелен и параллелен, как CMS, но внутри он работает иначе, чем старый сборщик мусора. Хотя G1 является поколенческим, в нем нет молодых и старых поколений, вместо этого каждое поколение представляет собой набор регионов, которые позволяют гибко изменять размеры.
Он разделяет размер кучи на набор областей одинакового размера и использует несколько потоков для их сканирования. После завершения фазы маркировки G1 узнает, в каком регионе больше мертвых объектов, и сначала выполняет сбор мусора в этом регионе.
Epsilon GC: Он был выпущен как часть JDK11 и представляет собой ничего не делающий сборщик мусора. Epsilon GC занимается распределением памяти, но не освобождает реальную память. Как только доступная куча Java будет исчерпана, JVM отключится (с ошибкой OutOfMemoryError). Итак, может возникнуть вопрос: зачем нам сборщик мусора, который не собирает мусор? Может быть вариант использования, когда мы знаем, что доступной кучи будет достаточно, и мы не хотим, чтобы JVM использовала какие-либо ресурсы для сборки мусора. Пример: Тестирование производительности.
Преимущества Java Gargabe Collection:Самое большое преимущество GC заключается в том, что вам не нужно беспокоиться о выделении и освобождении объектов после их использования, GC позаботится о них. GC обеспечивает эффективное использование памяти Java, поскольку GC удаляет неиспользуемые объекты из кучи для размещения вновь созданных объектов. Ряд инструментов позволяют отслеживать использование кучи и сборку мусора. Java предоставляет различные варианты настройки сборщика мусора для повышения его эффективности.