Почему финализаторы имеют «серьезное снижение производительности»? - PullRequest
24 голосов
/ 18 мая 2010

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

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

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

Ответы [ 6 ]

23 голосов
/ 18 мая 2010

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

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

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

10 голосов
/ 18 мая 2010

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

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

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

2 голосов
/ 18 мая 2010

Я только что поднял свою копию 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.

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

1 голос
/ 18 мая 2010

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

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

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

1 голос
/ 18 мая 2010

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

0 голосов
/ 18 мая 2010

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

...