这是内存泄漏还是误报?

45

这是我的代码:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Scanner;

public class temp {
    public static void main(String[] args) throws FileNotFoundException {
        BufferedReader a = new BufferedReader(new FileReader("a"));
        Scanner scanner = new Scanner(a).useDelimiter(",");
        scanner.close();
    }
}

我在使用 new Scanner(a) 时收到一个警告(我正在使用 jdk1.7.0_05 进行编译):

Resource leak: '<unassigned Closeable value>' is never closed.

我是做错了什么,还是这只是一个错误的警告?

4个回答

68

如果按照这种方式拆分代码,警告会消失吗?

  Scanner scanner = new Scanner(a);
  scanner.useDelimiter(",");
  scanner.close();

1
是的,当我像那样分割代码时,警告会消失。所以我的原始代码有内存泄漏吗? - dln385
4
不,这不是泄漏,而是编译器未能正确检测到的问题。 - Francis Upton IV
8
如果useDelimiter的实现返回除了"this"以外的任何东西(当前实现中没有这种情况),那就是一个泄漏。 - Bananeweizen
1
@Bananeweizen,如果useDelimiter的实现返回的不是this,那么即使使用这种解决方案也会有泄漏的风险。虽然useDelimiter的返回值从未被关闭,但情况已经很糟糕了。如果你不知道函数返回什么,那么没有办法防止这种泄漏,除非你进行双重关闭或类似的坏事。 - Earth Engine
5
实际上,useDelimiter 的名称和接口设计不太好。如果它的名称叫做 setDelimiter,并且返回类型像其他类似方法一样是 void,这将不再是一个问题。 - Earth Engine
显示剩余2条评论

13

是的,你的代码存在潜在(但不是真正的)内存泄漏问题。你将useDelimiter(a)的返回值赋给了局部变量scanner,但是构造函数的结果被丢弃了。这就是为什么你会收到警告。

实际上,useDelimiter(a)的返回值与构造函数调用返回的对象完全相同,因此你的代码可以正常关闭资源。但是编译器/代码分析工具无法检测到这一点,因为它必须了解useDelimiters的实现细节。

而且一个真正好的代码分析工具应该已经向你显示了一个额外的警告,因为你正在关闭一个在此方法中未被打开的资源(即useDelimiter的返回值)。如果你同时看到这两个消息,那么问题可能会更加明显。


1

你试过了吗:

Scanner scanner = new Scanner(new BufferedReader(new FileReader("a"))).useDelimiter(",");

如果它不起作用,你必须添加a.close();


当我把所有内容放在一行上时,仍然会收到警告。 - dln385
尝试在 main() 中删除 throws FileNotFoundException,并在 BufferedReader 周围添加一个 try/catch 块,在 finally 中加入 buff.close() - cl-r

0

是什么导致你收到这个警告?推测它之所以发出警告,是因为分配/关闭没有在try/finally块中完成,这通常不是一个好主意(在这种特定情况下不是问题,因为唯一可能抛出错误的是新的FileReader,如果它抛出错误,则实际上没有分配任何资源 - 但是这可以通过单个方法调用来改变..)

关闭扫描器会关闭底层流(确切地说是任何实现自己的Closeable的内容(是的BufferedReader也是如此),所以代码除此之外没问题。


我尝试将其放入try块中,并在finally块中关闭,但仍然收到警告。 - dln385
在这种情况下,无论您使用哪个静态分析工具,它都是静态分析器的错误。 - Voo
在这种情况下,try块是无法帮助的,因为如果在分配扫描器的语句中出现异常,则没有任何东西可关闭。 - Francis Upton IV
@Francis 是的,我们知道这一点,但有些情况下,工具(或程序员)无法确定是否会发生任何运行时异常,所以在所有情况下都发出警告似乎是一个简单的解决方案,以避免错误判断。 - Voo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接