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