Закрытие Input / OutputStreams при уничтожении? - PullRequest
12 голосов
/ 06 октября 2009

Есть ли InputStreams и OutputStreams в Java близко () при уничтожении? Я полностью понимаю, что это может быть дурной тон (особенно в мире C и C ++), но мне любопытно.

Также предположим, что у меня есть следующий код:

private void foo()
{
    final string file = "bar.txt";
    Properties p = new Properties();
    p.load( new FileInputStream(file) );
    //...
}

Выходит ли безымянный FileInputStream из области видимости после p.load () и, следовательно, уничтожается, как правила C ++? Я попытался найти в Google анонимные переменные области видимости для java, но это не помогло.

Спасибо.

Ответы [ 5 ]

18 голосов
/ 06 октября 2009

Первый ответ: в Java нет такого понятия, как «уничтожение» (в смысле C ++). Есть только сборщик мусора, который может или не может проснуться и сделать свою работу, когда он видит объект, который готов для сбора. GC на Java, как правило, не заслуживает доверия.

Второй ответ: иногда да, иногда нет, но не стоит рисковать. От Эллиота Расти Гарольда Java IO :

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

Согласно Гарольду, то же самое касается потоков ввода или вывода. Есть некоторые исключения (он отмечает System.in), но в целом вы рискуете, если не закроете файловые потоки, когда закончите. И закройте их в блоке finally, чтобы убедиться, что они закрываются, даже если выдается исключение.

6 голосов
/ 06 октября 2009

Раньше я предполагал, что потоки будут автоматически закрываться в конечном итоге через сборщик мусора, но неподтвержденные данные указывают на то, что отказ вручную закрыть их приводит к утечке ресурсов. Вместо этого вы захотите сделать что-то вроде этого:

InputStream stream = null;

try {
  stream = new FileInputStream("bar.txt");
  Properties p = new Properties();
  p.load(stream);
}
catch(Exception e) {
  // error handling
}
finally {
  closeQuietly(stream);
}

closeQuietly() - это метод IOUtils в библиотеке Apache commons-io.

5 голосов
/ 06 октября 2009

Нет, в Java нет деструкторов. Могут быть другие ссылки на объект, даже после того, как одна конкретная ссылка на него выходит из области видимости (или изменяется). Если объект более недоступен, поток может вызвать его финализатор через некоторое время, что закроет поток.

Properties.load своеобразно тем, что закрывает поток, переданный ему. Редактировать: Properties.loadFromXML - это особый метод, о котором я думал примерно пять лет назад. (Документ по API, вероятно, следует сказать до, а не после.) Спасибо @ tzimnoch.

3 голосов
/ 06 октября 2009

Короткий ответ: «Возможно, но не ставьте на это!».

Где-то в стеке классов, которые реализуют FileInputStream, есть класс с finalizer, который эффективно закроет поток (и освободит ресурс) при его запуске.

Проблема в том, что нет гарантии, что финализатор когда-либо будет работать. Цитирование из JLS (раздел 12.6):

Язык программирования Java не поддерживает укажите, как скоро будет финализатор вызывается, кроме как сказать, что это будет произойдет до хранения для объект используется повторно.

Это затрудняет завершение потока:

  1. Если ваш объект Stream никогда не станет мусором, он никогда не будет завершен.
  2. Если ваш объект Stream находится в постоянном владении, может пройти много времени, прежде чем он будет собран и завершен сборщиком мусора.
  3. JVM может потребоваться выполнить дополнительный цикл GC после того, как объект будет определен как недоступный до выполнения финализатора. Это, безусловно, разрешено JLS!
  4. Технически допустимо, чтобы JVM никогда и никогда не выполняла финализаторы при условии, что она никогда не использует хранилище объектов с финализаторами. (Я не знаю ни о каких JVM производственного качества, которые принимают эту линию, но вы никогда не знаете ...)
3 голосов
/ 06 октября 2009

Переменная выходит из области видимости и поэтому уничтожается. Но в Java существует очень большое различие между переменной и объектом , на который переменная указывает .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...