Input/OutputStreams закрывается на разрушении?

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

Это довольно просто:

  1. у меня должна была быть страница JSP в моем приложении (можно вставить его/WEB-INF, если Вы не хотите его внешне доступный).
  2. я записал пользовательское HttpServletResponse и ServletOutputStream, который получает содержание, записанное контейнером сервлета, и превращает его в Строку и полагался RequestDispatcher.include(...) для выполнения "запроса" к шаблону JSP (я также записал пользовательское HttpServletRequest для изоляции исходного запроса от мутации).
  3. , поскольку это - определенный взлом, а не способ, которым API сервлета был предназначен, чтобы использоваться, я инкапсулировал все это в служебном классе, так, чтобы весь клиентский код сделал, передать в пути к шаблону JSP и возвратить обработанное содержание.
12
задан Calyth 5 October 2009 в 21:01
поделиться

5 ответов

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

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

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

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

18
ответ дан 2 December 2019 в 04:17
поделиться

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

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.

6
ответ дан 2 December 2019 в 04:17
поделиться

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

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

3
ответ дан 2 December 2019 в 04:17
поделиться

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

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

5
ответ дан 2 December 2019 в 04:17
поделиться

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

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

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

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

Это делает завершение потока проблематичным:

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

Похожие вопросы: