Prevent memory leak in Android

Denys Vitali

I'm having some troubles with memory leaks on Android.
I do have a simple application with a relatively picture as background and it works fine, until I change the orientation.

The following is a graph showing the memory leak (allocated memory over time). Every spike corresponds to an orientation change, and every spike is +20M of allocated memory
Memory leak over time

At ~ 30 seconds the app crashes with an obvious "OutOfMemory" error:

Throwing OutOfMemoryError "Failed to allocate a 17469452 byte allocation with 804912 free bytes and 786KB until OOM"`

The layout is just a simple RelativeLayout with a jpeg image as background sized ~ 430k

I do have implemented also an onDestroy() anti-memory leak solution (as suggested here):

@Override
protected void onDestroy()
{
    unbindDrawables(view);
    view = null;
    System.gc();
    super.onDestroy();
}

private void unbindDrawables(View view) {
    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}

But it really don't change anything.

Is there anything I can do to solve the issue? I do need the image to be that big because the device running the app has a big screen.

-- Edit --
Adding onCreate() code as requested, please do note that the problem is present even without calling initMainView() and even by having an empty onCreate() (with super only), even tough the memory leak is inferior (only 0.8M) but still present.
I'm running Android 6.0.1 on a Pixel C, if that might help.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    System.gc();
    w = getWindow();
    w.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    dpm = (DevicePolicyManager) this.getSystemService(Context.DEVICE_POLICY_SERVICE);
    deviceAdmin = new ComponentName(this, AdmRcvr.class);

    if(!dpm.isDeviceOwnerApp(getPackageName())) {
        setContentView(R.layout.deviceownertutorial);
        final TextView tvTutorial = (TextView) w.findViewById(R.id.tutorialtv);
        tvTutorial.setText(Html.fromHtml(getString(R.string.deviceownertutorial)));

        final TextView tvDeviceOwnerError = (TextView) w.findViewById(R.id.tverrordeviceadmin);

        Button checkDeviceAdmin = (Button) w.findViewById(R.id.cdevadmin);
        checkDeviceAdmin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (dpm.isDeviceOwnerApp(getPackageName())) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setContentView(R.layout.startview);
                            initMainView();
                        }
                    });
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tvDeviceOwnerError.setText("App is not the device admin");
                            tvDeviceOwnerError.setVisibility(View.VISIBLE);
                        }
                    });
                }
            }
        });
    }
    else
    {
        setContentView(R.layout.startview);
        initMainView();
    }
}


public void initMainView(){
    // We're device owners!
    View mDecorView = w.getDecorView();
    mDecorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    mDecorView = null;
    view = findViewById(R.id.sv_relativelayout);
    initReader();
    initBitmapCache();
    enableTimer();
    currentStep = 1;
}

--- EDIT 2 ---

In the following images you could see the memory allocation in two situation: with all my app garbage (like the 430kB image) [a] and without (a clean onCreate()) [b].
Please do note that the memory leak is still present in both situation, as stated above, even tough it isn't that big (but there is!).

Memory leak in case [a] Memory leak, case [a]

Memory leak in case [b] Memory leak, case [b]

The app is compiled against SDK v.23 and with buildToolsVersion 23.0.2. The dependencies are the following:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
}

And the app/libs is the following:

libs
└── acssmc-1.1.2.jar  

--- EDIT 3 ---
When testing with a newly created application the memory is managed as it should, you could see an example on my GitHub repo

Denys Vitali

I've managed to solve the problem.
It was all because of a damn timer which was setting a tick event on every screen orientation change.
To fix the issue I simply binded the timer to a variable, and called timer.cancel() in onSaveInstance()

Now my memory leaks are gone (as shown below):
no more memory leaks

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Trying to prevent memory leak

From Dev

Android - RxJava vs AsyncTask to prevent getActivity() memory leak

From Dev

Possible to free Context from Singleton in Android to prevent memory leak

From Dev

Possible to free Context from Singleton in Android to prevent memory leak

From Dev

Set null to Thread to prevent memory leak in onDestroy Android

From Dev

How to prevent memory leak in code

From Dev

How to prevent memory leak in code

From Dev

Android animations memory leak

From Dev

Is it a memory leak in android

From Dev

memory leak with Android WebView

From Dev

Is it a memory leak in android

From Dev

Android - is this a memory leak?

From Dev

Android inner classes memory leak and leak by context?

From Dev

Setting pointers to nil to prevent memory leak in Golang

From Dev

How can this delete to prevent the memory leak?

From Dev

how to prevent ARC memory leak on iOS

From Dev

Android - Device Memory Leak with Fragments

From Dev

Android Fragment Webview Memory Leak

From Dev

Android runOnUiThread causing memory leak

From Dev

Android camera Bitmap memory leak

From Dev

Android progress bar memory leak

From Dev

`Unknown` (`Other`) memory leak in Android?

From Dev

Android runOnUiThread causing memory leak

From Dev

Getting Memory leak on android fragment

From Dev

Android memory leak Custom view

From Dev

Android memory leak on device, not on emulator

From Dev

Android Memory Leak - Anonymous class

From Dev

Avoid memory leak with WeakReference Android

From Dev

How to release memory in android to avoid memory leak