资源泄漏:“关闭”从未关闭


84

为什么Eclipse在以下代码中给我加温的“资源泄漏:'in'永远不会关闭”?

public void readShapeData() {
        Scanner in = new Scanner(System.in);
        System.out.println("Enter the width of the Rectangle: ");
        width = in.nextDouble();
        System.out.println("Enter the height of the Rectangle: ");
        height = in.nextDouble();

Answers:


69

因为您没有关闭扫描仪

in.close();

39
这将关闭Scanner和使警告静音,但也将关闭System.in,通常这是不希望的。
斯图尔特·库克

@StuartCook +1。需要注意的事情。
informatik01

7
为什么我们需要关闭扫描仪?什么是“资源泄漏”?
Erran Morad 2014年

1
@nogard:这对您的回答确实很有帮助..但是当我使用in.close(); ..它再次显示无法解决..我有一个没有异常处理的代码..谢谢
pcs

3
@StuartCook,您忘了提及为什么System.in通常不希望关闭的原因。这是因为您将无法再次读取它。即 java.util.NoSuchElementException: No line found如果您尝试致电(new Scanner(System.in)).nextLine(),您会得到。
彼得·博德纳(PetrBodnár)

55

正如其他人所说,您需要在IO类上调用“关闭”。我要补充一点,这是一个使用try的好地方-最终没有任何阻碍的块,如下所示:

public void readShapeData() throws IOException {
    Scanner in = new Scanner(System.in);
    try {
        System.out.println("Enter the width of the Rectangle: ");
        width = in.nextDouble();
        System.out.println("Enter the height of the Rectangle: ");
        height = in.nextDouble();
    } finally {
        in.close();
    }
}

这样可确保您的扫描仪始终关闭,以确保正确清理资源。

同样,在Java 7或更高版本中,可以使用“ try-with-resources”语法:

try (Scanner in = new Scanner(System.in)) {
    ... 
}

2
资源泄漏是什么意思,它将如何影响我?
Erran Morad 2014年

7
@Borat-“资源泄漏”表示某些系统资源(通常是内存)正在丢失或不必要地浪费。通常,这将在您开始在程序的正常运行期间引发OutOfMemoryError时影响您。
埃里克·林道尔

谢谢埃里克。我知道您可以通过在无限循环中向其自身附加字符串来导致错误。我不确定扫描仪如何导致该错误。
Erran Morad 2014年

4
尝试资源呢?
丹尼斯·蒙

谢谢丹尼斯,补充。
埃里克·林道厄

12

您需要in.close()finally块中以确保它发生。

从Eclipse文档中,这是为什么它标记了此特定问题的原因(重点是我的):

实现接口java.io.Closeable(从JDK 1.5开始)和java.lang.AutoCloseable的类(自JDK 1.7起)的类被视为代表外部资源,当不再需要它们时,可以使用close()方法关闭它们。

Eclipse Java编译器能够分析使用此类类型的代码是否遵守此策略。

...

编译器将使用“资源泄漏:'流'永远不会关闭”标记[违规]。

这里有完整的解释。


7

它告诉你,你需要关闭你实例化的扫描仪System.inScanner.close()。通常,每个读者都应该关闭。

请注意,如果关闭System.in,将无法再次读取它。您也可以看看Console课程。

public void readShapeData() {
    Console console = System.console();
    double width = Double.parseDouble(console.readLine("Enter the width of the Rectangle: "));
    double height = Double.parseDouble(console.readLine("Enter the height of the Rectangle: "));
    ...
}

3
请注意,System.console()当通过Eclipse运行应用程序时,此功能不可用,这在开发过程中可能会很麻烦。
斯图尔特·库克

6

如果您使用的是JDK7或8,则可以对资源使用try-catch。这将自动关闭扫描仪。

try ( Scanner scanner = new Scanner(System.in); )
  {
    System.out.println("Enter the width of the Rectangle: ");
    width = scanner.nextDouble();
    System.out.println("Enter the height of the Rectangle: ");
    height = scanner.nextDouble();
  }
catch(Exception ex)
{
    //exception handling...do something (e.g., print the error message)
    ex.printStackTrace();
}

请注意,catch子句不是强制性的。如果您只是想确保即使在发生异常的情况下也关闭了资源,但保留了OP原始代码中的异常处理方式(即,根本没有捕获),则可以try按所示使用,而不使用catch子句。
user118967

5
// An InputStream which is typically connected to keyboard input of console programs

Scanner in= new Scanner(System.in);

上一行将使用参数System.in调用Scanner类的Constructor,并将返回对新建对象的引用。

它连接到与键盘相连的输入流,因此现在在运行时,您可以接受用户输入以执行所需的操作。

//Write piece of code 

要消除内存泄漏-

in.close();//write at end of code.


3

private static Scanner in;并不能真正解决问题,只能清除警告。将扫描仪设为静态意味着它永远保持打开状态(或直到卸载该类为止,这几乎是“永远的”)。编译器不再警告您,因为您告诉他“请永远保持打开状态”。但这并不是您真正想要的,因为您应该在不再需要资源时立即关闭它们。

HTH,曼弗雷德。


2

通常,处理完I / O的类的实例应在完成后关闭。因此,在代码末尾可以添加in.close()


2
private static Scanner in;

我通过声明为私有静态Scanner类变量来修复它。不知道为什么要修复它,但这就是我建议的蚀。


5
您忽略了警告,但造成了资源泄漏
zacheusz 2014年

1

扫描仪应关闭。关闭阅读器,流……以及此类对象以释放资源和避免内存泄漏是一个好习惯。并在finally块中这样做,以确保即使在处理这些对象时发生异常,也将它们关闭。


这个答案实际上可以帮助OP知道为什么他应该关闭东西。当然,他可以阅读该文档并看到“ scanner.close()”,但是这个答案确实可以帮助他/她了解正在发生的事情。+1
HyperNeutrino,2015年

1

好的,至少在很多情况下,这实际上是一个错误。它也显示在VS Code中,这很容易引起注意,您已经到达了封闭范围的末尾而没有关闭扫描程序对象,但是没有意识到关闭所有打开的文件描述符是进程终止的一部分。不会发生资源泄漏,因为在终止时会清除所有资源,并且该过程将继续进行,不会留下任何资源来保存资源。


0
Scanner sc = new Scanner(System.in);

//do stuff with sc

sc.close();//write at end of code.

-1
in.close();
scannerObject.close(); 

它将关闭Scanner并关闭警告。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.