Почему финализаторы имеют "серьезное снижение производительности"?

Эффективная Java говорит:

Существует серьезное снижение производительности за использование финализаторов.

Почему медленнее уничтожить объект с помощью финализаторов?

6 ответов

Решение

Из-за того, как работает сборщик мусора. Для повышения производительности большинство Java GC используют копирующий сборщик, в котором недолговечные объекты размещаются в блоке памяти "eden", а когда пришло время собирать объекты этого поколения, GC просто нужно скопировать объекты, которые все еще "живы" в более постоянном пространстве памяти, и тогда он может стереть (освободить) весь блок памяти "eden" сразу. Это эффективно, потому что большая часть кода Java создает тысячи экземпляров объектов (примитивы в штучной упаковке, временные массивы и т. Д.) Со временем жизни всего несколько секунд.

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

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

Фактически столкнувшись с одной такой проблемой:

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

Это, конечно, в дополнение к многим другим причинам не использовать финализаторы, которые описаны в Effective Java.

Я только что снял свою копию Effective Java со своего стола, чтобы понять, на что он ссылается.

Если вы прочитаете главу 2, раздел 6, он подробно расскажет о различных показателях производительности.

You can't know when the finalizer will run, or even if it will at all. Because those resources may never be claimed, you will have to run with fewer resources.

Я бы рекомендовал прочитать весь раздел - он объясняет вещи намного лучше, чем я могу попугай здесь.

Если вы внимательно прочитаете документацию к finalize(), вы заметите, что финализаторы позволяют объекту предотвращать сбор GC.

Если финализатор отсутствует, объект просто может быть удален и больше не требует внимания. Но если есть финализатор, он должен быть проверен впоследствии, если объект снова не стал "видимым".

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

Моя мысль такова: Java - это язык для сборки мусора, который освобождает память на основе собственных внутренних алгоритмов. Время от времени GC сканирует кучу, определяет, на какие объекты больше нет ссылок, и освобождает память. Финализатор прерывает это и вынуждает освободить память вне цикла GC, что может привести к неэффективности. Я думаю, что лучшая практика заключается в использовании финализаторов только тогда, когда АБСОЛЮТНО необходимо, таких как освобождение файловых дескрипторов или закрытие соединений с БД, что следует делать детерминистически.

Одна из причин, по которой я могу придумать, заключается в том, что явная очистка памяти не нужна, если все ваши ресурсы - это объекты Java, а не собственный код.

Другие вопросы по тегам