代码之家  ›  专栏  ›  技术社区  ›  Leo Izen

正在GCED的输入流

  •  1
  • Leo Izen  · 技术社区  · 14 年前

    我知道如果我做类似的事情

    copyFromInToOut(new FileInputStream(f1), new FileOutputStream(f2));
    System.gc();
    

    它将运行GC FileInputStream S,关闭它们。但是如果我这样做

    copyFromInToOut(new BufferedInputStream(new FileInputStream(f1)), new BufferedOutputStream(new FileOutputStream(f2));
    System.gc();
    

    在bufferedOutputStream之前,是否存在导致缓冲区刷新的fileOutputStream被GCED的危险? 我不能叫Flush,Close,因为这需要更多的步骤。它首先涉及到声明一个bufferedInputstream,传递,然后调用close。或者我这样做安全吗?

    4 回复  |  直到 14 年前
        1
  •  8
  •   erickson    14 年前

    不要打电话 System.gc() 明确地。不要依赖终结器来做任何事情。尤其是如果你不理解垃圾收集是如何工作的。显式垃圾收集请求可以忽略,终结器可能永远不会运行。

    写得好的 copyFromInToOut 流的方法可能在内部使用自己的缓冲区,因此不需要包装输出。

    为声明变量 FileInputStream FileOutputStream 并调用 close() 在每一个 finally 块:

    FileInputStream is = new FileInputStream(f1);
    try {
      FileOutputStream os = new FileOutputStream(f2);
      try {
        copyFromInToOut(is, os);
        os.flush();
      } finally {
        os.close();
      }
    } finally {
      is.close();
    }
    
        2
  •  5
  •   Mike Q    14 年前

    没有我用will知道的inputstream实现 close() 当它是GCD的时候。你必须 关闭() 手动输入流。

    编辑 :显然,在我不知道的Finalize方法中,fileinputstream确实为您关闭了(),但请参阅其他答案,以了解您不应该依赖它的原因。

    在上面的两个示例中,必须同时关闭输入流和输出流。对于打包的缓冲区案例,对于任何打包的案例,只需调用 关闭() 在最外面 InputStream 在这种情况下 BufferedInputStream

        3
  •  2
  •   irreputable    14 年前

    好吧,当你这样做的时候分析到底发生了什么是很有趣的, 别那么做。

    始终显式关闭流。

    (要回答您的问题,是的,当GC发生并丢失时,缓冲区中的字节可能没有刷新到文件I/O流中)

        4
  •  2
  •   Stephen C    14 年前

    应该使用@erickson's answer中显示的模式显式关闭流。依赖终结为您关闭流是 真是馊主意 :

    1. 打电话 System.gc() 很昂贵,特别是因为(如果它做了什么)很可能触发一个完整的垃圾收集。这将导致 每个可到达对象中的每个引用 在您的堆中进行跟踪。

    2. 如果你阅读javadocs GC.() 您将看到,它只是对JVM运行GC的一个“提示”。JVM可以随意忽略提示…这就把我们带到下一个问题。

    3. 如果不显式运行GC,可能需要很长时间才能运行GC。即使如此,也不能保证终结器立即运行。

    同时:

    • 所有打开的文件都保持打开状态,可能会阻止其他应用程序使用它们。
    • 流中的任何未写入数据都保持未写入状态
    • 您的Java应用程序甚至可能遇到打开其他流来运行文件描述符时隙的问题。

    最后一个问题是依赖终结来处理输出流。如果在流完成时流中有未刷新的数据,则输出流类将尝试刷新它。但这都发生在一个JVM内部线程上,而不是应用程序的一个线程上。因此,如果刷新失败(例如,因为文件系统已满),您的应用程序将无法捕获产生的异常,因此无法报告它…或者做任何事来恢复。

    编辑

    返回到原始问题,结果发现BufferedOutputstream类不会重写默认值 Object.finalize() 方法。这意味着当bufferedOutputstrean被垃圾收集时,它根本不会被刷新。缓冲区中的任何未写入数据都将丢失。

    这也是显式关闭流的另一个原因。事实上,在这种情况下, GC.() 不仅是不好的做法,也是 可能的 导致数据丢失。