Search code examples
androidandroid-activityout-of-memory

Android not killing activities from stack when memory is low


We've been developing an application that has a drop down dashboard that allows the users to navigate throughout the app. The navigation is not very standard since this menu can be accessed from almost every activity. After playing for a while opening activities using the menu, the stack starts to grow and grow.

All these activities contain listviews with several imageviews inside, and they take around 3mb each. If the user plays enough and creates more than 25 activities on the stack this is what happens:

  1. Out of memory error is thrown (Heap is increased till there's no more heap).
  2. A dialog is shown due to the exception (Unfortunately, %activity% has stopped.)
  3. The activity where the outofmemerror was thrown is finished.
  4. All the activities in the stack are finished, but the history is kept, so its possible to backup and each activity is recreated automaticall by the OS.

I was expecting the system to kill the oldest activities in the stack automatically BEFRORE the OutOfMemoryError was thrown...

Just to be sure the OS is not killing old activities, I created a test app that allocates 1mb each time. Guess what: The behavior is the same and outofmemerror is thrown:

The question is: How can we tell the Android OS that it is allowed to deallocate activities and its resources if needed so we don't get the "Unfortunately, your activity has stopped." dialog?

Proof of concept

    package com.gaspar.memorytest;

import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MemoryTestActivity extends Activity { /** Called when the activity is first created. */ private byte[] mData; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main1); ((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent i = new Intent(MemoryTestActivity.this, MemoryTestActivity.class); startActivity(i); } }); mData = new byte[1*1024*1024]; } }


Solution

  • I was expecting the system to kill the oldest activities in the stack automatically BEFRORE the OutOfMemoryError was thrown

    Android does not do this. Android terminates processes to free up system memory for other processes. It does not get involved with intra-app memory usage in a similar fashion.

    How can we tell the Android OS that it is allowed to deallocate activities and its resources if needed so we don't get the "Unfortunately, your activity has stopped." dialog?

    You can't.

    Instead, you need to design your application to use fewer activities, or use fewer resources per activity. For example, you can "recycle" existing activity instances via FLAG_ACTIVITY_REORDER_TO_FRONT, or (as Mr. Tornquist pointed out), you can finish() activities manually yourself.

    After playing for a while opening activities using the menu, the stack starts to grow and grow.

    You should probably be using FLAG_ACTIVITY_REORDER_TO_FRONT on these menu items, so that you bring the existing activity forward in the task, rather than creating new ones each time.