Static references are cleared--does Android unload classes at runtime if unused?

后端 未结 4 810
眼角桃花
眼角桃花 2020-12-02 19:05

I have a question specific to how the classloading / garbage collection works in Android. We have stumbled upon this issue a few times now, and as far as I can tell, Android

相关标签:
4条回答
  • 2020-12-02 19:11

    I've seen similar strange behaviour with my own code involving disappearing static variables (I don't think this problem has anything to do with the volatile keyword). In particular this has come up when I've initialized a logging framework (ex. Crashlytics, log4j), and then after some period of activity it appears to be uninitialized. Investigation has shown this happens after the OS calls onSaveInstanceState(Bundle b).

    Your static variables are held by the Classloader which is contained within your app's process. According to google:

    An unusual and fundamental feature of Android is that an application process's lifetime is not directly controlled by the application itself. Instead, it is determined by the system through a combination of the parts of the application that the system knows are running, how important these things are to the user, and how much overall memory is available in the system.

    http://developer.android.com/guide/topics/processes/process-lifecycle.html

    What that means for a developer is that you cannot expect static variables to remain initialized indefinitely. You need to rely on a different mechanism for persistence.

    One workaround I've used to keep my logging framework initialized is for all my Activities to extend a base class where I override onCreate and check for initialization and re-initialize if necessary.

    I think the official solution is to use the onSaveInstanceState(Bundle b) callback to persist anything that your Activity needs later, and then re-initialize in onCreate(Bundle b) when b != null.

    Google explains it best:

    http://developer.android.com/training/basics/activity-lifecycle/recreating.html

    0 讨论(0)
  • 2020-12-02 19:15

    Both you (@Matthias) and Mark Murphy (@CommonsWare) are correct in what you say, but the gist seems lost. (The use of volatile is correct and classes are not unloaded.)

    The crux of the question is where initialize is called from.

    Here is what I think is happening:

    • You are calling initialize from an Activity *
    • Android needs more memory, kills the whole Process
    • Android restarts the Application and the top Activity
    • You call getInstance which will return null, as initialize was not called

    Correct me if I'm wrong.


    Update:
    My assumption – that initialize is called from an Activity * – seems to have been wrong in this case. However, I'll leave this answer up because that scenario is a common source of bugs.

    0 讨论(0)
  • 2020-12-02 19:19

    Static references are cleared whenever the system feels like it and your application is not top-level (the user is not running it explicitly). Whenever your app is minimized and the OS wants some more memory it will either kill your app or serialize it on fixed storage for later use, but in both cases static variables are erased. Also, whenever your app gets a Force Close error, all statics are erased as well. In my experience I saw that it's always better to use variables in the Application object than static variables.

    0 讨论(0)
  • 2020-12-02 19:35

    I have never in my life seen a static data member declared volatile. I'm not even sure what that means.

    Static data members will exist until the process is terminated or until you get rid of them (e.g., null out the static reference). The process may be terminated once all activities and services are proactively closed by the user (e.g., BACK button) and your code (e.g., stopService()). The process may be terminated even with live components if Android is desperately short on RAM, but this is rather unusual. The process may be terminated with a live service if Android thinks that your service has been in the background too long, though it may restart that service depending on your return value from onStartCommand().

    Classes are not unloaded, period, short of the process being terminated.

    To address the other of @sergui's points, activities may be destroyed, with instance state stored (albeit in RAM, not "fixed storage"), to free up RAM. Android will tend to do this before terminating active processes, though if it destroys the last activity for a process and there are no running services, that process will be a prime candidate for termination.

    The only thing significantly strange about your implementation is your use of volatile.

    0 讨论(0)
提交回复
热议问题