Почему finalize() не гарантирует вообще ничего
Вопрос звучит невинно: «зачем нужен finalize() и почему его не стоит использовать». Проверяют не знание синтаксиса — проверяют, понимает ли кандидат, что этот метод не даёт ни одной гарантии, на которую можно опереться в проде.
JVM не обязана вызывать finalize() вовремя. Не обязана вызывать его вообще, если процесс завершился штатно или объект стал недостижим прямо перед остановкой. Finalizer выполняется в отдельном потоке finalizer thread, и если один объект зависает в finalize() — очередь встаёт для всех остальных объектов, ожидающих финализации.
Есть и более неприятный сценарий: объект может «воскреснуть» внутри finalize(), если сохранить ссылку на this в каком-нибудь статическом поле. Тогда GC не соберёт его и на втором проходе — финализация вызывается ровно один раз за жизнь объекта.
public class ResourceHolder { private final FileInputStream stream;
public ResourceHolder(String path) throws IOException { this.stream = new FileInputStream(path); }
@Override protected void finalize() throws Throwable { stream.close(); super.finalize(); } }
Спросят следом: а как правильно освобождать ресурс, если не finalize(). Ответ — try-with-resources для явного управления жизненным циклом, либо Cleaner из java.lang.ref для случаев, когда закрытие руками невозможно. Cleaner тоже не даёт гарантии времени вызова, но хотя бы не тормозит GC и не позволяет объекту воскреснуть.
finalize() депрекейтнут с Java 9 не из вежливости — он ломает предсказуемость управления ресурсами, на которой держится весь код с файлами, сокетами и соединениями.
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки