Комментарии 26
Вообще-то, при таком сценарии файл будет закрыт когда файловый поток будет собран сборщиком мусора. То есть не требуются ни метод finalize, ни фантомные ссылки, ни ReferenceQueue.
Естественно. Только сборщик мусора срабатывает, когда памяти мало, ему плевать, если у вас мало файл-дескрипторов (нередка ситуация, когда процесс не может открыть, например, больше 1000 файлов, потому что ulimit так настроен). Это бомба замедленного действия, когда вы полагаетесь на сборщик мусора с открытыми файлами. Когда она выстрелит у каких-нибудь клиентов, вы поймёте, что чтобы исправить эту проблему, переделывать придётся слишком много.
Нет никакой разницы между
private FileInputStream file;
protected void finalize() throws Throwable {
file.close();
}
и тем же самым кодом, но без finalize()
. Когда объект уже собран сборщиком мусора — закрывать управляемые ресурсы поздно!
Я абсолютно не понимаю, зачем вы выделили "уже" курсивом и полужирным и как это относится к моему комментарию. А разница определённо есть: здесь вам потребуется три цикла сборки мусора, чтобы всё прибрать. А без finalize() только два.
То есть вы тоже согласны, что finalize()
тут лишний? Тогда как вы собрались с помощью finalize
делать кеширующий читатель большого файла?
Под "отказаться от finalize" подразумевалось не использовать его в том числе в объекте, который непосредственно держит ресурс (например, FileInputStream). Хотя это было писано четыре года назад. Сейчас PhantomReference даже в данном случае выглядит привлекательнее. Тем более, в Java 9 появится публичный Cleaner, который гораздо лучше finalize.
protected void finalize() throws Throwable {
this.rows = null;
this.tables = null;
this.frame = null;
....
}
Т.е. программист сознательно «занулял» все поля объекта. Сдается мне в корпоративных приложениях на вроде «Система внутреннего документа оборота ТраснКредитСельхозУнипроЛевобережного Банка» таких вещей оч. много.
1. Никогда, никогда не помогайте GC (особенно через finalize), только хуже сделаете.
2. Если возможно (т.е. вы не завязаны на legacy code) — не юзайте finalize(), мы кричим об этом годами, но никто не слышит.
3. Если все-таки необходимо завязываться на освобождение ресурсов — только <*>Reference. Не забудьте, * — подставить Soft/Weak/Phantom — по необходимости.
Немного разъясню вашу мысль. Давайте сделаем вот так:
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(object, queue);
После того, как
object
будет уже никому не нужен он добавится в queue
. Его можно будет забрать вот так:PhantomReference ref = queue.remove();
Понятно, что забирать и обрабатывать эти ссылки можно в своей нити. Стоит отметить, что
ref.get()
всегда возвращает null
, хотя object
и жив внутри приватного поля ссылки. Этот механизм позиционируется как более гибкий, чем
finalize()
. Хотя, если честно, когда я вижу такие кренделя в неспециальных проектах у меня по коже муражки идут.Finalize конечно, в большом мире java достаточно редко используемая вешь, но где используется Week/SoftReference вполне возможная ситуация, когда finalize будет необходим.
За пост — пять!
finalize и Finalizer