Java/Scala 对垃圾收集有啥保证?
Posted
技术标签:
【中文标题】Java/Scala 对垃圾收集有啥保证?【英文标题】:What guarantees does Java/Scala make about garbage collection?Java/Scala 对垃圾收集有什么保证? 【发布时间】:2014-11-01 03:03:20 【问题描述】:Play 框架有 play.api.libs.Files.TemporaryFile
,它持有对 File
的引用,并在 TemporaryFile#finalize()
中删除它。
case class TemporaryFile(file: File)
def clean(): Boolean =
file.delete()
def moveTo(to: File, replace: Boolean = false)
Files.moveFile(file, to, replace = replace)
override def finalize
clean()
我知道这有一些问题,例如,您可以填满整个磁盘而 JVM 感觉不需要 GC。
但这里我问的是程序的“正确性”,即没有磁盘空间限制的程序。
def foo()
val tempFile = TemporaryFile(new File("/tmp/foo"))
val inputStream = new FileInputStream(tempFile.file) // last use
try
println(inputStream.read())
finally
inputStream.close()
在我从文件中读取之前可以删除 /foo/bar 吗?我在// last use
之后不使用tempFile
,那之后可以马上定稿吗?
或者如果它作为参数传递给函数呢?
def foo()
val tempFile = TemporaryFile(new File("/tmp/foo"))
bar(tempFile)
def bar(tempFile: TemporaryFile)
val inputStream = new FileInputStream(tempFile.file) // last use
try
println(inputStream.read())
finally
inputStream.close()
如果在上面的示例中,tempFile
可能在我使用完毕之前被删除,TemporaryFile
的正确用法是什么,这样就不会发生这种情况?
【问题讨论】:
请注意,读取文件和File
实例之间没有任何关系,除了用于标识文件系统资源的名称。
@SotiriosDelimanolis,正确。
好问题。并且没有一个答案解决了在已经收集了 TemporaryFile 对象的情况下处理异步 Future 块中的 File
引用时可能发生的问题......我怀疑这会在我的应用程序上产生一个错误!
【参考方案1】:
一旦您不再拥有对该对象的强引用,Java 对象就有资格进行垃圾回收。这不取决于您是否“使用”该对象。
在这个例子中,
def foo()
val tempFile = TemporaryFile(new File("/tmp/foo"))
val inputStream = new FileInputStream(tempFile.file) // last use
try
println(inputStream.read())
finally
inputStream.close()
tempFile
不符合垃圾回收条件,因此在不再使用 foo()
之前完成。使用来自tempFile
的成员的对象可能会使用它,并使其不符合条件的时间超过foo()
中的最后一次使用时间。
在这个例子中,
def foo()
val tempFile = TemporaryFile(new File("/tmp/foo"))
bar(tempFile)
def bar(tempFile: TemporaryFile)
val inputStream = new FileInputStream(tempFile.file) // last use
try
println(inputStream.read())
finally
inputStream.close()
结果是一样的。
在一个小的变体中(Java,我不太了解 Scala 语法),
class Foo
List<Object> objects = new List<Object>();
void foo(Object o)
objects.add(o);
// ...
Foo f = new Foo();
f.foo(new Object()); // The object we just created is not eligible for garbage
// collection until the `Foo f` is not used, because
// it holds a strong reference to the object.
【讨论】:
@Dici ***.com/questions/9809074/… @Dici 我的意思是您的标准票价参考,没有多余的参考。弱引用是不阻止 GC 执行其业务的引用。见docs.oracle.com/javase/8/docs/api/java/lang/ref/… Java中有4种引用,强、软、弱、幻。进一步阅读:rallydev.com/community/engineering/…。基本强防止对象被GC tempFile 不符合垃圾回收的条件,因此在 foo() 返回之前完成 是错误的。由于在访问其file
字段后未使用tempFile
,因此它引用的对象在该访问后立即变为合格。
@SotiriosDelimanolis 我不明白,tempFile
在方法返回之前是可以访问的。【参考方案2】:
在执行退出其范围之前,局部变量不会被最终确定。 GC 不会终止您不使用的对象,它会终止您无法再访问的对象,因此在您使用 tempFile 的示例中,它不会在 foo() 调用之前发生完成了。
【讨论】:
作用域与 GC 关系不大。范围定义了您可以在何处使用某些实体的名称。即使包含局部变量的方法(或其他范围)尚未结束,局部变量引用的对象也可以被 GC'ed。 我的意思是局部变量不能在之前执行退出其范围,因为在这种情况下它显然是可访问的。但是,我确实知道在本地创建的对象在包含它的方法结束后可以继续存在。它更清楚,还是我应该更正我的答案? 我是说局部变量引用的对象可以在执行退出其(局部变量)范围之前死亡。 Scope 只处理程序中名称使用的有效性。以上是关于Java/Scala 对垃圾收集有啥保证?的主要内容,如果未能解决你的问题,请参考以下文章