好吧,所以我知道你应该总是关闭你的溪流和其他本地资源,但我目前还不确定原因。
我看到了原因之一,这是因为可用的资源有限,并且您希望在完成这些资源后立即将其释放。 但是我们假设您的应用程序没有使用那么多资源,那么就不需要关闭资源吗?
特别是因为你有finalize()
块,当GC到达它时应关闭所有本机资源。
答案 0 :(得分:1)
简单:你总是努力做正确的事。
使用诸如“它不使用很多资源”之类的假设来构建应用程序是一种错误的方法。相反:你专注于让你的逻辑正确。
你知道:真正的世界应用程序的东西是:当它们有用时,它们将被使用。只要您有用户,您就会处理其他要求。这样可以增强和维护代码。因此,你之前提出的任何“妥协”(“这只是一件小事,所以谁关心”)都有可能使这些活动比应该做的更加艰难。
换句话说:您应该努力构建“正确”的应用程序。你不写邋code的代码,因为它“无关紧要”。因为你经常无法预测你的代码在某些时候是否变得“重要” - 然后你的罪孽会再次咬你。
不,敲定不是任何答案(见here)。您关心代码正在使用的所有资源,并仔细确保资源具有明确定义的生命周期。
答案 1 :(得分:1)
首先,GC永远不会保证终结,因此你不能依赖它。
其次,在现实世界的应用程序中,您的应用程序所需的资源量会发生变化,因此您不应该依赖于假设,并且应该释放尽可能多的资源以提供最佳性能。
在我看来,关键词是效果,可用性,可扩展性。
答案 2 :(得分:1)
假设“你有finalize()
块,当GC到达它时应关闭所有本机资源”首先是错误的。没有保证代表本机资源的每个对象都有这样的finalize()
方法。
其次,资源不一定是native
资源
当你有,例如BufferedOutputStream
,ObjectOutputStream
或ZipOutputStream
包裹FileOutputStream
,后者可能有finalize()
方法来释放基础本机资源(依赖于实现) ),但是没有写出正确写入数据所需的包装流的任何未决数据。必须关闭包装器流以确保写入的输出完成。
天真地向这些包装器流类添加finalize()
方法以关闭它们是行不通的。当收集流对象时,它意味着没有对它的引用,换句话说,不再有定向的应用程序→包装器流→本机流图。由于对象图可以是循环的,因此无法保证在死对象中对订单进行昂贵的搜索会成功,这就是JVM甚至不尝试的原因。
或者,正如the specification所说:
Java编程语言对
finalize
方法调用没有排序。终结者可以按任何顺序调用,甚至可以同时调用。
因此,无法保证在基础本地流的finalize()
方法之前调用包装器的finalize()
方法,因此,底层本机流可能已在包装器之前完成并关闭流使得无法编写待处理数据。
兔子洞更深入。对象实例由代码根据需要由JVM维护,但代码可以优化以直接使用封装数据。如果包装器流类具有finalize()
方法,您可能会发现即使之前的也可以释放包装器实例,如finalize() called on strongly reachable object in Java 8中所述。
或者,简而言之,明确关闭是确保它恰好在正确的时间点发生的唯一方法。
答案 3 :(得分:0)
作为Java开发人员,您无法控制何时或甚至是否调用终结器。如果您的资源供应有限(例如,数据库连接),或创建必须提供服务的其他线程,或持有锁,或使用大量内存,那么您需要控制何时分配和释放它们。对于保持资源分配的含义并不总是很明显,并且只要应用程序的逻辑允许,最小化资源使用的范围和持续时间总是更安全。