Финализация, слабые, мягкие и фантомные ссылки и их влияние на сборку мусора в Java VM

Финализация и слабые, мягкие и фантомные ссылки

Некоторые приложения взаимодействуют со сборкой мусора с помощью финализации и слабых, мягких или фантомных ссылок.

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

Явная сборка мусора

Другой способ, с помощью которого приложения могут взаимодействовать со сборщиком мусора, - это явный вызов полной сборки мусора с помощью System.gc().

Это может привести к выполнению основной сборки, когда в этом нет необходимости (например, когда достаточно небольшой сборки), и поэтому в целом следует избегать. Влияние производительности явных сборщиков мусора можно измерить, отключив их с помощью флага -XX:+DisableExplicitGC, который заставляет виртуальную машину игнорировать вызовы System.gc().

Одно из наиболее часто встречающихся применений явной сборки мусора происходит с распределенной сборкой мусора (DGC) удаленного вызова метода (RMI). Приложения, использующие RMI, ссылаются на объекты в других виртуальных машинах. Мусор не может быть собран в этих распределенных приложениях без периодического вызова сборки мусора из локальной кучи, поэтому RMI периодически выполняет полные сборы. Частота этих сборов может контролироваться с помощью свойств, как в следующем примере:

java -Dsun.rmi.dgc.client.gcInterval=3600000
    -Dsun.rmi.dgc.server.gcInterval=3600000 ...

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

Мягкие ссылки (Soft References)

Мягкие ссылки дольше сохраняются в виртуальной машине сервера, чем в клиенте.

Скорость очистки можно контролировать с помощью параметра командной строки -XX:SoftRefLRUPolicyMSPerMB=<N>, который указывает количество миллисекунд (мс), в течение которого мягкая ссылка будет оставаться активной (после того, как она станет недостижимой) для каждого мегабайта свободного места в куче. Значение по умолчанию - 1000 мс на мегабайт, что означает, что мягкая ссылка будет сохраняться (после того, как будет собрана последняя сильная ссылка на объект) в течение 1 секунды на каждый мегабайт свободного места в куче. Это приблизительный показатель, поскольку мягкие ссылки очищаются только во время сборки мусора, что может происходить время от времени.

Метаданные класса

Классы Java имеют внутреннее представление в виртуальной машине Java Hotspot и называются метаданными класса.

В предыдущих выпусках Java Hotspot VM метаданные класса выделялись в так называемой постоянной генерации. Начиная с JDK 8, постоянное поколение было удалено, а метаданные класса размещены в собственной памяти. Объем собственной памяти, которую можно использовать для метаданных класса, по умолчанию не ограничен. Используйте параметр -XX:MaxMetaspaceSize, чтобы установить верхний предел для объема собственной памяти, используемой для метаданных класса.

Java Hotspot VM явно управляет пространством, используемым для метаданных. Пространство запрашивается у ОС и затем разделяется на куски. Загрузчик классов выделяет пространство для метаданных из своих чанков (чанк привязан к определенному загрузчику классов). Когда классы выгружаются для загрузчика классов, его фрагменты перерабатываются для повторного использования или возвращаются в ОС. Метаданные используют пространство, выделенное mmap, а не malloc.

Если -XX:UseCompressedOops включен и -XX:UseCompressedClassesPointers используется, то для метаданных класса используются две логически разные области собственной памяти. -XX:UseCompressedClassPointers использует 32-битное смещение для представления указателя класса в 64-битном процессе, как -XX:UseCompressedOops для ссылок на объекты Java. Регион выделен для этих указателей сжатого класса (32-битные смещения). Размер области может быть установлен с -XX:CompressedClassSpaceSize и составляет 1 гигабайт (ГБ) по умолчанию. Пространство для сжатых указателей классов зарезервировано как пространство, выделенное -XX:mmap при инициализации и зафиксированное по мере необходимости. -XX:MaxMetaspaceSize применяется к сумме зафиксированного сжатого пространства классов и пространства для метаданных других классов.

Метаданные класса освобождаются, когда соответствующий класс Java выгружается. Java-классы выгружаются в результате сборки мусора, и сборщики мусора могут вызывать выгрузку классов и освобождение метаданных классов. Когда пространство, выделенное для метаданных класса, достигает определенного уровня (отметка верхнего уровня), запускается сборка мусора. После сборки мусора отметка максимального уровня может быть повышена или понижена в зависимости от количества места, освобожденного от метаданных класса. Верхняя отметка будет повышена, чтобы не вызывать очередной сбор мусора слишком рано. Начальная отметка изначально установлена на значение параметра командной строки -XX:MetaspaceSize. Он повышается или понижается в зависимости от параметров -XX:MaxMetaspaceFreeRatio и -XX:MinMetaspaceFreeRatio. Если выделенное пространство, доступное для метаданных класса в процентах от общего выделенного пространства для метаданных класса, больше, чем -XX:MaxMetaspaceFreeRatio, тогда верхняя отметка будет понижена. Если оно меньше -XX:MinMetaspaceFreeRatio, тогда верхняя отметка будет повышена.

Укажите более высокое значение для параметра -XX:MetaspaceSize, чтобы избежать ранних сборок мусора, вызванных для метаданных класса. Количество метаданных класса, выделенных для приложения, зависит от приложения, и общие рекомендации по выбору -XX:MetaspaceSize отсутствуют. Размер по умолчанию -XX:MetaspaceSize зависит от платформы и составляет от 12 МБ до 20 МБ.

Информация о пространстве, используемом для метаданных, включена в распечатку кучи. Ниже приведен типичный вывод:

[0,296s][info][gc,heap,exit] Heap
[0,296s][info][gc,heap,exit] garbage-first heap total 514048K, used 0K [0x00000005ca600000, 0x00000005ca8007d8, 0x00000007c0000000)
[0,296s][info][gc,heap,exit] region size 2048K, 1 young (2048K), 0 survivors (0K)
[0,296s][info][gc,heap,exit] Metaspace used 2575K, capacity 4480K, committed 4480K, reserved 1056768K
[0,296s][info][gc,heap,exit] class space used 238K, capacity 384K, committed 384K, reserved 1048576K

В строке, начинающейся с Metaspace, значение used - это объем пространства, используемого для загруженных классов. Значение capacity - это пространство, доступное для метаданных в выделенных в настоящее время фрагментах. committed значение - это количество места, доступного для чанков. reserved значение - это количество места, зарезервированного (но не обязательно выделенного) для метаданных. Строка, начинающаяся с class space, содержит соответствующие значения для метаданных для сжатых указателей классов.


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки