当前位置: 首页 > 知识库问答 >
问题:

使用扫描程序时的资源泄漏警告[重复]

孟成化
2023-03-14

我正在看一些Java教程,对使用扫描器时的资源泄露警告感到疑惑。

我知道我可以关闭它,但视频中的人没有得到警告,即使他使用的是完全相同的代码,为什么呢?

    Scanner input= new Scanner(System.in);
    
    System.out.print("Enter a line of text: ");
    String line = input.nextLine();
    
    System.out.println("You entered: " + line);
    
    //input.close();

共有1个答案

戚正业
2023-03-14

这是..很复杂。一般规则是,无论谁创建资源,都必须安全地关闭它,因为您的代码创建了一个扫描器,IDE会告诉您:嘿,您应该关闭它。

问题是,关闭扫描器在这里是错误的:扫描器环绕system.in,这不是您创建的资源,但是scanner.close()会关闭底层流(system.in本身),而您不希望这样:这不是您的责任,实际上是在积极地危害事物;现在你再也读不到赛辛了。

问题是,IDE不能真正知道这一点。潜在的问题是system.in在许多方面都是设计极差的API,但[A]它已经有30年历史了,在那时要知道这一点要困难得多;我们现在知道这一点是因为事后才知道的,[B]oracle还没有开发sysin/out/err API的第二个版本,它也不是议程上的优先级。

这就给IDE带来了麻烦:设置一些使用资源的模式和规则相对容易,这样您就不会有任何问题使用这种“您创建的筛选器来包装您没有创建的资源”,但是您不能在不编写一些框架的情况下将它们与sysin/err/out一起使用,这对新手来说是一个很高的要求。这也不是一个好主意,大概是告诉那些在Java编码方面迈出第一步的人,先下载一些第三方库,稍微清理一下sysin/out/err交互。

因此,我们处于边缘状态。IDE不应该对此发出警告,但他们很难察觉这是一个异国情调的sccenario,在这里,您创建了一个资源,但却不需要关闭,事实上,也不应该关闭。

你可以关闭“未关闭资源”的设置,这无疑是视频教程所做的,但这是一个有用的警告。只是..被这个愚蠢的旧API所阻碍,它再也没有意义了。

有资源。这些是实现autoclosable的东西,而且非常多。让我们关注那些表示I/O事物的类型:层次结构中的顶级类型是Writer、Reader、InputStream和OutputStream(我们将它们统称为WRIO)。它们都是可自动关闭的,并且大多数IDE(不正确吗?)所有这些都抱怨未关闭的资源。然而,这是过于简单化的事情。

你可以把世界上所有的WRIO分成:

  • 实际资源(它们直接表示一个基础的基于OS的概念,如果您不关闭它们,它会导致某些资源的匮乏,也称为“泄漏”)。new fileInputStreamsocket.getInputStream等,这些表示实际资源
  • 虚拟资源--它们的作用类似于一个资源,但实际上并不代表一个您可以饿死的、垃圾回收器尚未修复的资源。新建ByteArrayInputStream,将StringBuilder转换为读取器等。
  • 筛选器-这些筛选器环绕资源并在“传输”时修改它。这样的过滤器本身并不捕获任何可饥饿的资源。如果您close()它们,它们还会在它们包装的东西上调用close。扫描仪是一个筛选器。

关闭它们的规则归结为:

  • 实际资源-必须安全关闭由谁制造的资源。如果您没有这样做,则会发出IDE警告。请注意,您没有使system.in,因此不适用于此处。
  • 虚拟资源-您可以关闭它们,但不必关闭。如果IDE对它们发出警告,那么就在它周围抛出一个试用资源,这很烦人,但并不太难处理。
  • 筛选器-很棘手。

如果它是为您提供的一个过滤器,目的是关闭它:

BufferedReader br = Files.newBufferedReader(somePath);

则无法关闭br是资源泄漏;允许使用IDE警告。

如果它是你做的过滤器,围绕着你也做的WRIO:

InputStream raw = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(raw, StandardCharsets.UTF_8));

(这是一个真实资源,由一个筛选器WRIO(InputStreamReader)包装,然后由另一个筛选器WRIO包装):那么资源泄漏是关于raw的,如果您不能安全地关闭br,那就不是资源泄漏。这可能是一个bug(如果您关闭raw而不首先关闭/刷新br,缓冲区中的一堆字节将不会被写出),但不是资源泄漏。IDE警告无法关闭br是错误的,但并不是太有害,因为您可以在它周围抛出试用资源,这也可以保证“由于无法清除缓冲过滤器WRIO而导致的错误”不再发生。

然后,就是问题案例:

制作一个筛选器WRIO来包装一个您没有制作的资源,也没有责任关闭它:您不应该主动关闭这些筛选器WRIO,因为这将最终关闭基础资源,而您不希望这样做。

在这里,IDE警告是非常糟糕和令人讨厌的,但是IDE很难意识到这一点。

通常情况下,你可以通过不进入那种场景来解决这个问题。例如,System.in应该有更好的API;这个API看起来像:

try (Scanner s = System.newStandardIn()) {
   // use scanner here
}

并且具有关闭s本身并不关闭system.s的属性(它基本上什么也不做;设置一个布尔标志,以便在执行任何进一步的读取调用时抛出异常,或者甚至可能什么也不做)。现在IDE的警告充其量是过分热心的,但是听从它的建议并安全地关闭扫描器现在就不再积极地在代码中引入bug了。

不幸的是,那个好的API还不存在(现在?)。因此,我们陷入了一个恼人的场景,一个有用的IDE警告系统由于糟糕的API设计而主动误导您。如果你真的想,你可以这样写:

public static Scanner newStandardIn() {
    Scanner s = new Scanner(System.in) {
        @Override public void close() {}
    };
    // hey, while we're here, lets fix
    // another annoying wart!

    s.useDelimiter("\r?\n");
    return s;
}

现在,你可以听从它的建议,听从这些警告:

public static void main(String[] args) {
    String name;
    int age;

    try (Scanner s = newStandardIn()) {
        System.out.print("What is your name: ");
        // use next() to read entire lines -
        // that useDelimiter fix made this possible
        name = s.next();
        System.out.print("What is your age: ");
        age = s.nextInt();
    }

    // use name and age here
}

没有IDE警告,也没有bug。

 类似资料:
  • 我正在读取一个文件并将其内容存储在字符串中。代码给了我一个警告:Resource leak:。我如何解决它?

  • 大家好,我的程序员们。 我有一些代码,spring工具套件编辑器的反应也不一样,也许你们一些聪明人知道为什么。 有人能告诉我为什么这是不可能的吗: 但这是!? 第一行代码给了我一个警告“Resource leak:unassigned closeable value is never close”,正如您所看到的,我在try/catch中使用了一个finally,如果对象不为空,它应该总是关闭对象

  • 在中,我收到了一个警告,我不明白这一点。 这是理解问题还是java/eclipse问题?

  • 我是个新手。我已经编写了这段代码,它显示那里存在资源泄漏 这是什么意思?抱歉,我太天真了。

  • 在这段代码的第4行,有一个资源泄漏警告。输入=扫描(); 我想要一个从用户那里获取整数的方法。它会要求用户重新输入一个整数值,如果他以前输入的值是不可接受的,即字符、规格。字符等。此外,我想在返回所取的int之前关闭扫描仪。 如何解决这个问题?

  • 我使用一个用不同长度的不同值填充字节数组。我使用方法。由于此方法继承自,因此可能会引发IOException。在中有一个方法不会引发IOException,因此我扩展了并覆盖方法,该方法现在也不会引发IOException: 对于扩展类,我在eclipse 4.5.1中得到了资源泄漏的警告,因为我没有关闭代码中的流。的情况并非如此。我的扩展类有什么问题,或者我需要添加什么来删除警告?我知道我可以将