Singleton with object declarations gets garbage collected


#1

Hi all,

I am writing an Android application in which I used object declaration for my data model as a singleton. The declaration is as the following:

object DataManager {
    lateinit var currentBox: Property
        private set
    
    fun getProfileById(permission: Permission, id: Int, callback: Callback<Config>) {
        val config = realm.where(Config::class.java).equalTo("xid", currentBox.xid).equalTo("_permission", permission.value()).equalTo("dbId", id).findFirst()
        ...
    }

and I am running to an exception whenever my app is resumed from background.

Caused by kotlin.UninitializedPropertyAccessException: lateinit property currentBox has not been initialized
at com.ahed.ringo.model.DataManager.getProfileById(DataManager.kt:416)
at com.ahed.ringo.guestdetail.GuestDetailPresenter.loadProfile(GuestDetailPresenter.kt:42)
at com.ahed.ringo.guestdetail.GuestDetailPresenter.updateView(GuestDetailPresenter.kt:254)
at com.ahed.ringo.BasePresenter.bindView(BasePresenter.kt:19)
at com.ahed.ringo.guestdetail.GuestDetailActivity.onResume(GuestDetailActivity.kt:54)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1277)
at android.app.Activity.performResume(Activity.java:7088)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3768)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3832)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2994)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1631)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6682)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

It looked like that the property is garbage collected and reinitialized to null. I thought singleton declared in this way won’t be wiped out from memory but it doesn’t seem to be the case now. Can someone advise the proper way to declare a singleton using kotlin? Or is there anything wrong in my code?

Thanks a lot.


#2

Do you have a reference to DataManager somewhere, or do you only call functions on it like DataManager.getProfileById(...)? If you do the latter, then nobody holds a reference to the instance of DataManager. I believe, the garbage collector is then free to collect the instance. The next time you invoke a function on DataManager again, the instance is recreated and currentBox will be null again.

I am not 100% sure that this is the case, but it is worth investigating. Something like this:

object DataManager {
    init {
        println("Initializing DataManager")
    }
    
    ...
}

#3

This is the way it is supposed to work. If you have application specific “things” the way to do so is to override the Application class and to do initialisation (and referencing there). This will allow it to be loaded whenever your application is active, and be independent from services, activities etc.


#4

@pdvrieze Thank you for your reply. I thought Kotlin’s object declarations are like static object in Java and thus won’t be garbage collected. If they might still be garbage collected then this might not be a proper solution for singleton usage as it is mentioned here.


#5

Just a beginnersquestion, but I thought this was not possible…

In java, a collection can be garbage collected if the refcount is 0.
The object is stored in a static field, so the refcount cannot be 0.
the stored object has a ref to the currentbox.
then, the refcount to currentbox cannot be 0

Where am I missing the point?


#6

If you do not store the instance yourself, then the Java class is the only object that references the instance. And as you probably also don’t hold a reference to the class, it (together with its instance) may be garbage collected.

The next time you try to retrieve the instance, the class is loaded again, and the instance is reinitialized.

Again, I am not 100% sure that this is happening, but some logging/debugging should clear things up.


#7

This is yet another example of why Kotlin is inferior to Java as it does not provide support for real static class references. The Kotlin “singleton” with static-like syntax is a recipe for bugs like this.


#8

Guys, are you really sure this was a garbage collection rather than an application just having been restarted?

That’s how it should be: an instance of a singleton object is kept in a static field inside the class of that object. Therefore it isn’t eligible to the garbage collection.

@orino, could you ensure how the lateinit currentBox property is initialized? Probably it doesn’t happen on all code paths the application could take during the startup?


#9

@ilya.gorbunov

I am pretty sure cuz it is my activity being restored. I would rather that android framework restart my application so that I wouldn’t have to deal with the intermediate state issue in this case.


#10

So, Android is the problem.
I forgot it was about Android when reading this…


#11

@ilya.gorbunov, @DonWills

Of course you are correct. An instance referenced through a static field should have the same visibility as the static field itself.

Given the Android context, there is no requirement however for android to keep any part of the application around if it is not “active”. In short, for Android even more than in general, don’t use static fields / globals / objects to store any form of persistent state.

If you want something to happen whenever your application starts (whatever way that is, as service, some activity, any other entry point), you should register an Application subclass in your manifest.