资源泄漏:'in'永远不会关闭,尽管它已关闭

时间:2013-01-10 10:27:21

标签: java java-io

我知道有几个类似的有问题的问题,但大多数人只是忘记在他们的流上加上close()指令。这是不同的。

假设我有以下最小的例子:

public void test() throws IOException
{
    InputStream in;
    if( file.exists() )
    {
        in = new FileInputStream( file );
    }
    else
    {
        in = new URL( "some url" ).openStream();
    }
    in.close();
}

这在Eclipse(Juno SR1)中给出了Resource leak: 'in' is never closed警告。 但是当我将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();
    }
}

这里发生了什么?

6 个答案:

答案 0 :(得分:6)

由于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。我的感觉,而且我现在没有运行Juno,就是它看到InputStream'in',可能会通过所有的箍和障碍来达到你将要使用它的程度。不幸的是,正如有人指出的那样,你的代码对于一个例子来说有点狡猾。按照我和@duffymo的详细说明这样做,你将摆脱警告。

答案 1 :(得分:5)

以下是我写的方式:

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 :(得分:4)

我怀疑警告不正确。它可能会检查您是否在同一范围内关闭流。在第二种情况下,您没有关闭第二个流。

答案 3 :(得分:0)

如果文件不存在并且您尝试关闭不存在的文件,则可能无法初始化您的输入。

你的第二个例子也需要一个密切的声明来避免泄密。

答案 4 :(得分:0)

当您在打开资源后显式抛出异常时,可能会发生同样的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方法的习惯,确保资源正确且一致地被关闭。

答案 5 :(得分:0)

我有类似的东西:

InputStream content = httpResponse.getEntity()==null?null:httpResponse.getEntity().getContent();

给出相同的warrning。但如果我这样离开它:

InputStream content =httpResponse.getEntity().getContent();

我没有收到任何补偿。不奇怪还是什么?

- 我希望我的信息能够为原始问题添加知识。谢谢!

相关问题