Будут ли потоковые классы или соединения рассматриваться как утечка ресурсов в Java

В Java нет времени жизни объекта, этим управляет garbage collector. И если я использую некоторые классы ввода-вывода, не закрывая его, или некоторые DBConnection, будет ли это считаться утечкой ресурсов? Другими словами, будет ли объект ввода-вывода собираться и уничтожаться сборщиком мусора, насколько мне известно, сборщик мусора предназначен только для памяти. Например:

BufferedReader br = new BufferedReader( new FileReader( new File("path") ) );

person Joey.Z    schedule 29.08.2013    source источник


Ответы (3)


Да ты прав.

Сборка мусора освобождает кучу Java (память), но close() освобождает ресурсы ОС, используемые для открытия файла (количество открытых файлов ограничено в большинстве систем), и гарантирует, что данные действительно записываются.

Но многие классы, такие как FileInputStream и RandomAccessFile, написаны с использованием метода finalize(), который гарантирует, что ЕСЛИ экземпляр в собранном мусоре, close() будет вызываться первым. Таким образом, во многих случаях сборка мусора косвенно освобождает файлы, и программисты часто могут лениться закрывать ресурсы, потому что сборка мусора обычно очищает их за вас. К сожалению.

Проблема в том, что вы не можете контролировать, когда это происходит, а может и не произойти вовсе. Поэтому, если у вас открыто слишком много файлов, операционная система может выдать вам сообщение об этом до того, как сборщик мусора успеет их закрыть. Или, если вы хотите переместить файл или удалить его, сразу после его чтения - перемещение или удаление может завершиться неудачей, потому что в этот момент файл все еще открыт для чтения.

Подобные ошибки часто сложно надежно воспроизвести, потому что они зависят от времени работы сборщика мусора. Таким образом, вы получаете вещи, которые обычно работают нормально, но иногда загадочным образом дают сбой. Очень раздражает отладка. По этой причине настоятельно рекомендуется обязательно закрыть() любой поток/читатель/соединение или другой закрываемый ресурс, который вы можете использовать, как только вы закончите с ним. Предпочтительно в блоке finally, чтобы гарантировать, что это произойдет, даже если при обработке произойдет какая-то другая ошибка.

А с Java 7 добавлен интерфейс AutoClosable, подробнее об этом читайте здесь.

Ссылка: http://www.coderanch.com/t/278165//java/InputStream-close-garbage-collection

person Amar    schedule 29.08.2013
comment
Так что, это! Я где-то читал о finalize, и это объясняет, зачем он нам нужен. Но я также читал, что не полагайтесь на finalize как насчет этого утверждения? - person Joey.Z; 29.08.2013
comment
@zoujyjs Использование finalize просто создаст дополнительные накладные расходы на GC. Закрытие должно быть сделано через try..catch..finally. Но если это не может быть гарантировано, вы можете использовать finalize. - person Sajal Dutta; 29.08.2013
comment
Добавляя к входу Саджала выше, в основном вы не должны полагаться ни на что другое и явно закрывать свои потоки/соединения, когда закончите с этим. - person Amar; 29.08.2013

And if I use some IO classes without closing it, or some DBConnection, will
this considered a resource leak?

Использование одних и тех же классов ввода-вывода - неправильная терминология. Если вы создаете ресурс/соединение, а затем используете его ссылку для какого-либо другого ресурса, фактически не закрывая исходный ресурс, тогда, если нет активных ссылок на исходный ресурс, он будет иметь право на сборщик мусора.

Однако до тех пор, пока исходный ресурс не будет проверен, все ресурсы ОС (дескрипторы файлов и т. д.) не будут освобождены. Когда объект будет подвергнут GC (для этого объекта/ресурса вызывается метод finalize()), сначала вызывается close(), из-за которого освобождаются ресурсы, связанные с ОС, а затем память кучи.

Например, рассмотрим метод finalize() FileInputStream следующим образом.

protected void finalize() throws IOException {
    if ((fd != null) &&  (fd != FileDescriptor.in)) {

        /*
         * Finalizer should not release the FileDescriptor if another
         * stream is still using it. If the user directly invokes
         * close() then the FileDescriptor is also released.
         */
        runningFinalize.set(Boolean.TRUE);
        try {
            close();
        } finally {
            runningFinalize.set(Boolean.FALSE);
        }
    }
}

Вы видите, что close() вызывается первой.

Таким образом, хотя GC позаботится об управлении памятью за вас, хорошей практикой программирования является закрытие ресурса в операторе finally, когда он вам не нужен.

person Aniket Thakur    schedule 29.08.2013

«В Java нет времени жизни объекта, им управляет сборщик мусора». -Не совсем верно. Во-первых, это «управляется» способом написания программы. Если объект выходит за рамки, GC, скорее всего, позаботится об этом.

Если вы не закроете br, он будет жить до тех пор, пока программа не завершит работу, пока не будет собран сборщиком мусора, если он готов к сбору. Он не протекает, просто долгоживущая переменная.

person Sajal Dutta    schedule 29.08.2013
comment
Он будет жить до тех пор, пока не получит право на GC и не пройдет GCed; это может быть, а может и не быть время жизни приложения. - person Dave Newton; 13.10.2016
comment
@DaveNewton Да, это правильно, но в худшем случае - этого не произойдет, и вы также не можете заставить. Вы можете захотеть привлечь его внимание вызовом System.gc(), но это не гарантирует сбор. Я должен отредактировать формулировку. - person Sajal Dutta; 14.10.2016