I am using a system which needs to initialize many objects using transactions, and for reasons beyond the scope of this question these transactions must be passed into the constructors. Like this:
trait Mutable
class Txn(i: Int) {
def newID(implicit m: Mutable): Int = i
override def finalize(): Unit = println("Finalised " + i)
}
class User(t0: Txn) extends Mutable {
val id = t0.newID(this)
}
Now I am fearing there is a problem with garbage collecting the transactions:
val u = new User(new Txn(1234))
System.gc() // hmmm, nothing seems to happen?
So my question is: Does the t0
constructor argument ever get garbage collected, or do I create a memory leak here? In an equivalent Java code, I guess I'd have something like this:
public class User implements Mutable {
final int id;
public User(Txn t0) {
id = t0.newID(this);
}
}
and I am sure t0
is collected. But is this true in the Scala case?
If not, how can I ensure t0
is garbage collected? Remember that I must pass in the transaction as a constructor argument, because the User
class implements some traits which must be passed into Txn
's methods, thus those methods (like newID
) cannot be called before constructing User
.
I have tried before to construct everything that uses the transaction outside of the user object, with tons of lazy
interdependent vals, but that was really messy. For example, this, which is already halfway unreadable, produces a stack overflow:
trait User extends Mutable { def id: Int }
def newUser(implicit tx: Txn): User = {
lazy val _id: Int = tx.newID(u)
lazy val u = new User { val id: Int = _id } // oops, should be lazy val id!
u
}
val u = newUser(new Txn(1234))
You can imagine that it really sucks that the compiler won't spot the problem with the missing lazy val here, so I would definitely prefer the constructor arg variant.
An object is eligible to be garbage collected if its reference variable is lost from the program during execution. Sometimes they are also called unreachable objects. What is reference of an object? The new operator dynamically allocates memory for an object and returns a reference to it.
An object is eligible for garbage collection when there are no more references to that object. References that are held in a variable are usually dropped when the variable goes out of scope. Or, you can explicitly drop an object reference by setting the variable to the special value null.
We have three ways to achieve same - 1) Increasing the Heap -Eden space size . 2) Create Singleton class with Static reference . 3) Override finalize() method and never let that object dereference.
You can't force garbage collection in Java. There are some strategies you can use to get the Java virtual machine to prioritize the task, but the indeterminate nature of garbage collection means the process can't be forced. Similarly, you can't stop Java garbage collection from happening, either.
Constructor arguments get GCed if they are not used beyond the static initializer. You can check the bytecode and verify that no reference to the constructor argument is preserved in this case.
class WillNotStore(s: Seq[Int]) { val length = s.length }
public WillNotStore(scala.collection.Seq);
Code:
0: aload_0
1: invokespecial #18; //Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: invokeinterface #22, 1; //InterfaceMethod scala/collection/SeqLike.length:()I
11: putfield #11; //Field length:I
14: return
Note that the argument is loaded (line 5) and a method is called on it (line 6), but only the answer is stored (line 11) before the constructor quits (line 14).
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