В Java у нас есть память стека и память кучи. Примитивные значения и ссылки на объекты хранятся в стеке. Фактические объекты хранятся в куче. Эти объекты кучи содержат примитивные значения, а также ссылки на другие объекты кучи. Память стека автоматически очищается. Когда метод завершает выполнение, значения и переменные для этого метода забываются, потому что нет возможности вернуться к выполнению метода и нет смысла хранить их дальше.
Но как насчет кучи памяти? Когда метод завершается, память кучи не очищается автоматически, поскольку объект в куче все еще может потребоваться другому методу, который все еще находится в стеке. В результате память кучи будет жить дольше, чем память стека. Вы не можете вручную очистить память кучи в Java. Сборщик мусора — это процесс JVM, очищающий динамическую память.
Сборщик мусора освобождает память кучи, снова делая ее доступной для приложения. Это верно не для всех языков. В C, например, вам как разработчику придется самостоятельно освобождать память, что отлично работает, если все сделано правильно. Разрешение JVM обрабатывать это во время процесса сборки мусора устраняет многие распространенные проблемы и ошибки, допускаемые разработчиками.
Право на вывоз мусора
Когда объект больше не имеет ссылки на стек, он удаляется сборщиком мусора. Другими словами, сборщик мусора считает его готовым к удалению.
JVM должна определить, когда будет происходить сборка мусора. Код Java не имеет на это никакого влияния. Возможно, вы заметили, что вы можете указать Java запустить сборку мусора с помощью system.gc, но это ничего не гарантирует.
System.gc()
Этап сбора мусора
- Изготовление -
У нас есть куча, полная объектов, и мы какое-то время игнорируем сборщик мусора Java и пытаемся сами думать как сборщики мусора. Итак, как нам определить, какие объекты не имеют подключения к стеку?
То, что он делает, зависит от конкретной реализации сборщика мусора, но ему всегда нужно делать некоторую маркировку живых объектов, чтобы он знал, что непомеченные объекты могут быть удалены. Эта маркировка может происходить различными способами. Карта с адресом памяти, ключами и значениями состояния объекта, например, будет подходить, как это принято для маркировки объектов. Память тоже занимает эта карта с пометками.
2. Подметание -
После маркировки живых объектов пришло время удалить немаркированные объекты. На жаргоне сборки мусора это удаление известно как очистка. Конечно, иметь только один метод подметания было бы скучно. Вместо этого у нас есть три варианта очистки: нормальная уборка, уплотняющая уборка и копирующая уборка.
Обычная уборка -
Участки памяти здесь не отмечены, поэтому их можно удалить. Это то, что происходит после того, как вы что-то удалили. Это та же память, но со свободными блоками пространства между ними. Итак, если мы хотим сохранить новый бит, подобный этому, JVM посмотрит на кучу и определит, что он может храниться там вот так.
Подметание с уплотнением -
Итак, у нас есть память, и эти биты не помечены, поэтому они будут зачищены. Мы не просто удалим эти биты и оставим пробелы, а воспользуемся ими для сжатия памяти, чтобы после сжатия она выглядела вот так. И если мы хотим сохранить большее значение сейчас, у нас есть достаточно большой блок памяти, и мы не получим ошибку нехватки памяти.
Подметание с копированием -
Здесь у нас другая память, но на этот раз у нас есть дополнительная часть памяти, потому что мы собираемся копировать. Это биты, которые не отмечены и поэтому могут быть удалены; однако вместо того, чтобы удалять их и затем сжимать память, мы просто скопируем отмеченные элементы в другую область памяти, а затем удалим весь блок в первой области памяти.
Разные поколения в куче
На самом деле Java различает разные типы памяти кучи. Это важно для алгоритмов сборки мусора. Java разделяет память кучи, чтобы ею можно было управлять более эффективно. У нас в куче есть и молодое, и старое поколения. Также у нас есть еще один раздел, несмотря на то, что технически это некучная память. Ранее это было известно как постоянное поколение, но начиная с Java 8 оно было заменено метапространством.
Идея состоит в том, что большинству объектов Java не нужно жить долго, и они будут существовать только короткое время. Поскольку это область памяти, в которой создаются новые объекты, она должна поддерживать очень быстрое выделение памяти. Это молодое воспоминание фактически разделено на две части: пространство Эдема и пространство выжившего. В пространстве Эдема создаются новые объекты, и при достижении определенного порога начинается сборка мусора, а объекты, которые еще живы, перемещаются в пространство выживших, очищая пространство Эдема.
Когда приходит выбор мусора для пространства оставшихся в живых, объекты, которые все еще доступны в молодом поколении в пространстве оставшихся в живых, перемещаются в старое поколение, где они, скорее всего, останутся в течение некоторого времени. Остальных увозят. Очистка — это копирование объектов из молодого поколения в старое. В результате сборщиков, которые этим занимаются, называют мусорщиками. В результате все это поколение содержит объекты, открытые молодым поколением. И выживание в этом цикле сборки мусора обычно указывает на то, что объекты будут существовать какое-то время. Это старшее поколение также хорошо обеспечено.