Утечка ресурсов: "in" никогда не закрывается, хотя закрыт
Я знаю, что есть пара аналогично названных вопросов, но большинство из них просто забыли поставить директиву close()
на свой поток. Это другое.
Допустим, у меня есть следующий минимальный пример:
public void test() throws IOException
{
InputStream in;
if( file.exists() )
{
in = new FileInputStream( file );
}
else
{
in = new URL( "some url" ).openStream();
}
in.close();
}
Это даст мне предупреждение Resource leak: 'in' is never closed
в Eclipse (Juno SR1).
Но когда я перемещаю in.close()
в условный блок, предупреждения исчезают:
public void test() throws IOException
{
InputStream in;
if( file.exists() )
{
in = new GZIPInputStream( new FileInputStream( file ) );
in.close();
}
else
{
in = new URL( "some URL" ).openStream();
}
}
Что здесь происходит?
Ответы
Ответ 1
Вот как я его напишу:
public void test() throws IOException
{
InputStream in = null;
try {
if(file.exists()) {
in = new FileInputStream( file );
} else {
in = new URL( "some url" ).openStream();
}
// Do something useful with the stream.
} finally {
close(in);
}
}
public static void close(InputStream is) {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Ответ 2
Из-за исключения IO вы можете столкнуться с утечкой ресурсов (по-настоящему)
Попробуйте сделать следующее:
public void test() throws IOException
{
InputStream in= null;
try {
if( file.exists() )
{
// In this case, if the FileInputStream call does not
// throw a FileNotFoundException (descendant of IOException)
// it will create the input stream which you are wrapping
// in a GZIPInputStream (no IO exception on construction)
in = new GZIPInputStream( new FileInputStream( file ) );
}
else
{
// Here however, if you are able to create the URL
// object, "some url" is a valid URL, when you call
// openStream() you have the potential of creating
// the input stream. new URL(String spec) will throw
// a MalformedURLException which is also a descendant of
// IOException.
in = new URL( "some url" ).openStream();
}
// Do work on the 'in' here
} finally {
if( null != in ) {
try
{
in.close();
} catch(IOException ex) {
// log or fail if you like
}
}
}
}
Выполнение вышеизложенного позволит убедиться, что вы закрыли поток или, по крайней мере, приложили все усилия для этого.
В исходном коде у вас был объявлен InputStream, но он не был инициализирован. Для начала это плохая форма. Инициализируйте это значение как null, как показано выше. Мое чувство, и на данный момент я не запускаю Юнону, это то, что он видит, что InputStream 'in', может потенциально пройти через все обручи и препятствия, чтобы добраться до точки, в которой вы собираетесь ее использовать. К несчастью, как заметил кто-то, ваш код немного изволен для примера. Выполняя это, как я подробно описал, а также @duffymo, вы избавитесь от предупреждения.
Ответ 3
Я подозреваю, что предупреждение неверно. Это может быть проверка того, что вы закрываете поток в той же области. Во втором случае вы не закрываете второй поток.
Ответ 4
Поток не может быть инициализирован, если файл не существует, и вы пытаетесь закрыть несуществующий файл.
В вашем втором примере также потребуется закрыть инструкцию, чтобы избежать утечек.
Ответ 5
Эта же отчетность Eclipse может произойти, когда вы явно бросаете исключение после того, как вы открыли свой ресурс, например:
public void method() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
while (br.ready()) {
String line = br.readLine():
if (line.length() > 255) {
throw new IOException("I am some random IOException");
}
}
br.close();
}
Это какой-то надуманный код для демонстрационных целей, поэтому не выглядите слишком сложно.
Если кто-то должен был прокомментировать строку, предупреждение исчезнет. Конечно, вы хотите убедиться, что этот ресурс закрыт должным образом. Вы можете сделать:
if (line.length() > 255) {
br.close();
throw new IOException("I am some random IOException");
}
Не полагайтесь на предупреждения Eclipse в этом случае. Получите привычку использовать метод try/finally, чтобы убедиться, что ресурсы правильно и последовательно закрыты.
Ответ 6
У меня есть что-то вроде:
InputStream content = httpResponse.getEntity()==null?null:httpResponse.getEntity().getContent();
который дает тот же самый warrning. Но если я оставлю это так:
InputStream content =httpResponse.getEntity().getContent();
Я не получаю никаких обвинений. Не странно или что?
- Я надеюсь, что моя информация добавит знания в исходный вопрос. Спасибо!