2013-08-29 44 views
3

Java对象没有生命周期,这由garbage collector管理。如果我使用某些IO类而不关闭它,或者某些DBConnection,这会不会考虑资源泄漏?也就是说,IO对象是否会被垃圾收集器AFAIK收集并销毁,垃圾收集器仅用于内存。例如:将流类或连接视为Java中的资源泄漏

BufferedReader br = new BufferedReader(new FileReader(new File("path"))); 

回答

4

是的你是对的。垃圾收集释放Java堆(内存),但close()释放用于打开文件的操作系统资源(在大多数系统上打开文件的数量是有限的),并确保数据真正写入。

但是很多类如FileInputStreamRandomAccessFile都是用一个finalize()方法编写的,该方法确保了如果垃圾回收的close()实例将被首先调用。所以在很多情况下,垃圾回收会间接释放文件,程序员通常可能懒得关闭资源,因为垃圾回收通常会为您清理它们。不幸。

问题是,您无法控制何时发生这种情况,而且可能根本不会发生。所以如果打开的文件太多,操作系统可能会在垃圾收集器关闭它们之前给你一个错误信息。或者,如果您想在移动文件或删除文件后立即阅读文件,移动或删除操作可能会失败,因为那时您仍然可以打开文件以供阅读。

像这样的错误往往难以可靠地重现,因为它们取决于垃圾回收器的时间。所以你得到的东西通常工作得很好,但有时会神秘地失败。非常烦人的调试。出于这个原因,我们强烈建议您尽快关闭()您可能正在使用的任何流/读取器/连接或其他可关闭资源。最好在finally块中,确保即使在处理中发生其他错误时也会发生这种情况。

而且随着Java 7的推出,还增加了一个接口AutoClosable,详细了解它吧here

价:http://www.coderanch.com/t/278165//java/InputStream-close-garbage-collection

+0

就这样!我在某处读到了“敲定”,这解释了为什么我们需要它。但我也读过,不要依赖'敲定'这个声明怎么样? – zoujyjs

+2

@zoujyjs使用“finalize”只会创建额外的GC开销。关闭应该通过try..catch..finally完成。但如果无法保证,您可能需要使用finalize。 –

+0

在上面添加到Sajal的输入中,基本上你不应该依赖其他任何东西,并且当你完成它时明确关闭你的流/连接。 – Amar

1

“Java对象没有生命周期,这是由垃圾收集器管理的。” - 不完全正确。它首先由程序编写的方式“管理”。如果一个对象超出范围,GC很可能会处理它。

如果您不关闭br,它将一直存在,直到程序退出,除非通过GC收集,如果准备收集。它不会泄漏,只是一个漫长的生活变量。

+0

它将一直存在,直到它符合GC的条件并且是GCed;这可能是也可能不是应用程序的生命周期。 –

+0

@DaveNewton是的,这是正确的,但最坏的情况是 - 它不会,你也不能强迫。您可能希望通过System.gc()调用来引起其注意,但不保证收集。我应该编辑措辞。 –

1
And if I use some IO classes without closing it, or some DBConnection, will 
this considered a resource leak? 

使用相同IO类说是错误的术语。如果您创建资源/连接,然后在不实际关闭原始资源的情况下使用其资源的引用,那么如果没有对原始资源的活动引用,那么它将符合GC的条件。

但是,直到原始资源被GCed时,所有的操作系​​统资源(文件句柄等)都不会被释放。当对象受到GC(在该对象/资源上调用finalize()方法)时,首先调用close(),因为释放了与操作系统有关的资源,然后释放堆内存。

例如,考虑的FileInputStream finalize()方法是如下

protected void finalize() throws IOException { 
    if ((fd != null) && (fd != FileDescriptor.in)) { 

     /* 
     * Finalizer should not release the FileDescriptor if another 
     * stream is still using it. If the user directly invokes 
     * close() then the FileDescriptor is also released. 
     */ 
     runningFinalize.set(Boolean.TRUE); 
     try { 
      close(); 
     } finally { 
      runningFinalize.set(Boolean.FALSE); 
     } 
    } 
} 

你看近()首先调用。

因此,尽管GC为您处理内存管理,但在不需要它时关闭finally语句中的资源是一种很好的编程习惯。