简体   繁体   中英

background image memory leak

I found few topics describing similar problems, but not found a solution for memory leaks being created by pretty simple Android app:

AndroidManifest.xml :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="cz.reloecc.testBackground"
          android:versionCode="1"
          android:versionName="1.0">
    <uses-sdk android:minSdkVersion="10"/>
    <application android:label="@string/app_name"
              android:icon="@drawable/ic_launcher">
        <activity android:name="TestBackgroundActivity"
                  android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>


main.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:background="@drawable/ui">
</LinearLayout>


TestBackgroundActivity.java :

public class TestBackgroundActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}


While changing an orientation of my device (nvidia Tegra Note 7) logcat is noting:

cz.reloecc.testBackground I/dalvikvm-heap﹕ Grow heap (frag case) to 35.625MB for 12904976-byte allocation

with roughly 13MB addition on every turnaround (for biggest version of image)

up to my heap max (64MB):

cz.reloecc.testBackground E/dalvikvm-heap﹕ Out of memory on a 12904976-byte allocation.
cz.reloecc.testBackground I/dalvikvm﹕ at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
..
cz.reloecc.testBackground I/dalvikvm﹕ at cz.reloecc.testBackground.TestBackgroundActivity.onCreate(TestBackgroundActivity.java:13)


BUT! problem does not persist when I delete ui.png (which is set as background) from drawable-land-[x|m|l]dpi OR drawable-[x|m|l]dpi folder in res folder.. so if I have only one version of background image, I can turn device for a long week..

And here is my question: How to handle multiple versions of drawables (set as background) to avoid memory leaks?


//EDIT: I managed few tries of disposing, recycling, destroying, nulling resources or their holders, the last one is based on Aeshang's suggestion:


=== version 2.0 ===

Resources.java :

public class Resources {

    public Resources(Context context){
        this.context = context;
    }

    public Drawable getImage(int id){
        if(images.indexOfKey(id) < 0){
            Drawable drawable = context.getResources().getDrawable(id);
            images.put(id, drawable);
        }

        return images.get(id);
    }

    public void disposeImages(){
        int key;

        for(int i = 0; i < images.size(); i++) {
            key = images.keyAt(i);
            Drawable drawable = images.get(key);

            if(drawable instanceof BitmapDrawable){
                if(drawable instanceof BitmapDrawable){
                    Log.i(TestBackgroundActivity.LOG_TAG, "Recycling image " + key);
                    ((BitmapDrawable)drawable).getBitmap().recycle();
                }
            }
        }
    }

    public void disposeAll(){
        disposeImages();
        images.clear();
    }

    private SparseArray<Drawable> images = new SparseArray<Drawable>();
    private Context context;
}


TestBackgroundActivity.java :

public class TestBackgroundActivity extends Activity {

    public static String LOG_TAG = "[TestBG]";

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        resources = new Resources(getApplicationContext());
        LinearLayout mainLayout = (LinearLayout)findViewById(R.id.mainLayout);
        mainLayout.setBackgroundDrawable(resources.getImage(R.drawable.ui));
    }

    @Override
    protected void onDestroy(){
        resources.disposeAll();

        super.onDestroy();
    }

    private Resources resources;
}

Use third party libraries to load the drawables

like Picasso or Universal Image Loader

They will automatically handle large bitmaps

And coming to drawables

User 1920X1080 resolution images and put them drawable-xxhdpi folder every thing works fine

Ok,

this should definitely work. Tested in on two other devices, and altrough app is complaining about high memory heap grow. It is gc'ing right after.

My tegra note 7 is THE pain. I will have to find out the right source of this hell.

//edit: fine, calling

System.gc();

in onDestroy() of MainActivity

and app lasts forever.. who knows why?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM