Вопрос

So, here is a known method to share data between activities and avoid frequent loading and releasing resources. However, I read an article (which was referred to on Android official website) that says using a static field might result in memory leak. I am not entirely sure whether these two concepts are the same or not. Would anyone be able to shed some light on it? Any help is appreciated.

Code for my static data holder:

public class Art {

    public static Bitmap enemy;
    public static Bitmap player;

    public static void load () {
        enemy = loadBitmap('enemy.png');
        player = loadBitmap('player.png');
    }

    private static Bitmap loadBitmap(String filename) {
        //create and return bitmap here
    }

}

Code for context memory leak:

private static Drawable sBackground;

@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);

  TextView label = new TextView(this);
  label.setText("Leaks are bad");

  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);

  setContentView(label);
}
Это было полезно?

Решение

Variables declared as static are created once the first instance of the class are created, or the first reference to that variable is called. This means that the object will live for the whole application lifetime and there's no way they will be removed from memory unless you explicitly set to NULL.

This being said, your static variable can be used in any way you want, but you need to be careful not to assign to it an object that you expect to deallocate. A simple example

public class Foo {
    static MyObject object;
    static void setObject(MyObject obj)
    {
        object = obj;
    }
}

Using Foo.setObject(someObject) would cause someObject never to be deallocated, because the static variable lives forever and is pointing to someObject, hence it will never be garbage collected.

A more complicated example:

public class Foo {
    static MyObject object;
    static void setBar(Bar bar)
    {
        object.bar = bar;
    }
}

Here the story is the same. bar will not be garbage collected because object.bar is pointing to it, and object is static. This is what happens in the example you pasted.

label.setBackgroundDrawable(sBackground);

public class Label { // just to illustrate the concept
    void setBackgroundDrawable(Drawable d) {
        // If d is static, callback is pointing to the label and will not be deallocated
        d.callback = this;
    }
}

Of course, you would need to know how setBackgroundDrawable works (which I didn't until reading the link you posted) in order to draw the conclusion that it could lead to a leak.

Другие советы

The article says that you should keep in mind what a particular object references internally when storing this object in a static variable.

This mainly depends on the parameters you use when creating the object. For Bitmap in particular this may be another Bitmap or a Matrix (depending on called createBitmap() method) but not e. g. a Context or a complete View-hierarchy.

So if you really need these bitmaps very often it is ok to store them in static variables.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top