Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android memory leak with static final

The question is on using static final constants which apparently causes memory leaks: I have been searching for information on how not to cause memory leaks in Android Apps. One big problem is using private static final for constants. Apparently that is how constants should be defined. But static final means it hangs around after a rotation and means the Activity cannot be cleared.

Obviously I am misunderstanding something. I know that putting variables in the Application context allows them to hang around without causing problems.

As a general question on memory leaks: There are lots of information on memory leaks, but I cannot find anything that sums up all the information clearly. Any recommendations where it is all fully explained.

like image 828
DerekD Avatar asked Dec 01 '22 00:12

DerekD


2 Answers

This information is incorrect. Making a variable static final will not cause any kind of memory leaks just because it was marked static final. That is not to say you can't create memory leaks by doing that though. One thing you want to make sure to avoid is creating a static variable that is of type context (such as activity). When you create a static reference to a context you are possibly creating a memory leak. A static variable means there is only one copy of that variable for your entire application and across instances of that class. It also means that it will remain in memory until it is explicitly cleared or the application is shutdown. Static variables are class level variables and are not attached to any specific instance of an object. When you create for example a 'public static final string myString = "Hello"' you will never be causing a memory leak. This way of define a constant will actually save memory vs using 'public final string myString = "Hello"' because without static a memory location will be created to store that string for every instance of this class instead of just having one copy for all instances to use.

like image 178
Bobbake4 Avatar answered Dec 03 '22 13:12

Bobbake4


in Java, Static variables live on the heap, and are allocated when their class loads. Instance variables' garbage collection eligibility is tied to their instance.

Using value-type(int, bool, double, etc.) static variables will not leak instances of the class. When you allow non-value-type static variables, you can leak anything referenced by these static variables.

Consider a simple class

public class Activity extends Context {
    static int willNotLeakActivity = 0;
    static Context mayLeakActivity = new Context();

    //if you call activityA.leakyMethod(activityA); you will leak activityA
    public void leakyMethod(Context context){
        mayLeakActivity = context;
    }

    //this method won't leak the instance
    public void safeMethod(int arg){
        willNotLeakActivity = arg;
    }
}

if you keep references to Activity objects (even if the reference type is Context) in static variables, you'll leak the Activity object.

Keep in mind that Android doesn't run on a real JVM, but on the Dalvik VM, so your results may vary in theory, but I'd be very surprised to find that Dalvik differs as far as GC eligibility is concerned (I haven't run into any issues myself).

Edit - Looking again at the question, I think this may clear up some understanding: An object won't become eligible for garbage collection as long as it can be reached by following reference chains from GC roots. Activity objects are instantiated and kept alive normally by the Android process (which i assume is kept alive with something at least analagous to static void main(string[] args).

Once the system calls yourActivityInstance.onDestroy() and releases the refefence, that object is eligible to be GCed (and subsequently, all objects it references), UNLESS the instance of your activity is reachable from a GC root through another reference. If this reference is held longer than it should be held (read: indefinitely), you've leaked this object, since GC can't be sure that it can safely free the leaked object's resources.

It doesn't matter how this reference is held (static or non-static, final or non-final). As long as an object can be reached from a GC root (at least local and in-scope variables in static methods, static fields in loaded classes), you're going to leak.

like image 44
Chris Bye Avatar answered Dec 03 '22 12:12

Chris Bye