Do companion objects remain in memory for app's lifecycle
instance of the class (MyClass) remains in memory for the entire lifecycle of the app?
Companion object in JVM
in kotlin
class MyClass {
companion object {
fun doSomething() {
}
}
}
MyClass(Kotlin) converted in JVM
public final class MyClass {
public static final MyClass.Companion Companion = new MyClass.Companion(null);
public static final class Companion {
public final void doSomething() {
}
private Companion() {
}
public Companion() {
this();
}
}
}
As above code, companion object
is declared as Companion
class in JVM, and it's created as static
field inside MyClass
class. Thus, isn't collected by gc. So, the memory of object(Companion) is remained during the ProcessLifecycle
. static final object
isn't released in normal case.
In conclusion, if referred to MyClass.Companion
instance in application, that instance will not be garbage collected. (on general Classloaders).
*If not referred to MyClass.Companion
instance in application, it may be removed by code shrinking feature.
Is there a way in Android Studio to check to see if this is the case?
You can see through android studio > profiler > Heap dump.
Reference
- https://developer.android.com/topic/performance/memory-overview
- https://developer.android.com/studio/build/shrink-code
As you seem to know and the above answer also makes clear that companion objects are translated to classes, and the class which declares them holds a static reference to the object of companion class, something as following:
public static final MyClass.Companion Companion = new MyClass.Companion(null);
Now the question
Do companion objects remain in memory for app's lifecycle
because the declaring class holds a static
reference to companion class, the question reduces to the life time of static
fields in jvm class
and the answer lies in the JVM spec, but the spec is bit dry on the explanation so I am adding some snippets from the book Inside the Java Virtual Machine.
As in your example let say we have a class
with nothing but single companion object.
First question is when an object of companion class will be created ? or
when static
fields are initialized ?
relevant text from the book. (for context the book is talking about class loading procedure)
Initialization
The final step required to ready a class or interface for its first active use is initialization, the process of setting class variables to their proper initial values. As used here, a "proper" initial value is the programmerís desired starting value for a class variable. A proper initial value contrasts with the default initial value given to class variables during preparation. As described above, the virtual machine assigns default values based only on each variableís type. Proper initial values, by contrast, are based on some master plan known only to the programmer. In Java code, a proper initial value is specified via a class variable initializer or static initializer.
So we know that once MyClass
is loaded and initialized, the object of companion class will be created.
but what would cause JVM to load MyClass
?
The Java Virtual Machine specification gives implementations flexibility in the timing of class and interface loading and linking, but strictly defines the timing of initialization. All implementations must initialize each class and interface on its first active use. An active use of a class is:
The invocation of a constructor on a new instance of the class
The creation of an array that has the class as its an element type
The invocation of a method declared by the class (not inherited from a superclass)
4 The use or assignment of a field declared by the class (not inherited from a superclass or super interface), except for fields that are both static and final, and are initialized by a compile-time constant expression
So as per 4th point when you do MyClass.foo()
from kotlin or MyClass.Companion.foo()
at this point MyClass
will be loaded and ready. (Probably a lot early)
Please note that at this point no object of MyClass
exist, that is we haven't used expression MyClass()
.
Does this mean static
fields will remain in memory as long as the application is running ?
They can be garbage collected if the declaring type gets unloaded, in our case if JVM or ART (on android) unloads the MyClass
then there is a possibility that companion object will be Garbage collected.
JVM Spec has following to say about class unloading
An implementation of the Java programming language may unload classes.
A class or interface may be unloaded if and only if its defining class loader may be reclaimed by the garbage collector as discussed in §12.6.
Classes and interfaces loaded by the bootstrap loader may not be unloaded.
In practicality class unloading almost(I said almost) never happens, so yes companion objects will remain in memory for app's life cycle.