The Play framework has play.api.libs.Files.TemporaryFile
that holds a reference to a File
, and deletes it in the 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()
}
}
I know that there are some issues with this, for example, you could fill up the entire disk without the JVM feeling the need to GC.
But here I ask about the "correctness" of a program, i.e. a program with no limit on disk space.
def foo() {
val tempFile = TemporaryFile(new File("/tmp/foo"))
val inputStream = new FileInputStream(tempFile.file) // last use
try {
println(inputStream.read())
} finally {
inputStream.close()
}
}
Could /foo/bar be deleted before I've read from the file? I don't use tempFile
after // last use
, so could it be finalized immediately after that?
Or what if it is passed as an argument to a function?
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()
}
}
If in the example above, tempFile
may be removed before I am done using it, what is the correct use of TemporaryFile
so that this does not happen?
Java objects are eligible for garbage collection once you no longer has a strong reference to the object. This is not dependent on if you "use" the object or not.
In this example,
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
is not eligible for garbage collection, and therefore finalization, until foo()
is is no longer used. It's possible that objects that use members from tempFile
may use it, and keep it ineligible longer than the last use inside foo()
.
In this example,
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()
}
}
The result is the same.
In a minor variant (Java, I don't know Scala syntax well),
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With