Monday, October 15, 2018

Monitor memory related events with onTrimMemory(), and simulate memory low in Android Emulator using adb

Android can reclaim memory from your app or kill your app entirely if necessary to free up memory for critical tasks. To help balance the system memory and avoid the system's need to kill your app process, you can implement the ComponentCallbacks2 interface and override onTrimMemory() callback method to listen for memory related events when your app is in either the foreground or the background, and then release objects in response to app lifecycle or system events that indicate the system needs to reclaim memory. 

When the system begins killing processes in the LRU cache, it primarily works bottom-up. The system also considers which processes consume more memory and thus provide the system more memory gain if killed. The less memory you consume while in the LRU list overall, the better your chances are to remain in the list and be able to quickly resume.

Here is a example code to implement the ComponentCallbacks2 interface and override onTrimMemory() callback method.

package com.blogspot.android_er.androidontrimmemory;

import android.content.ComponentCallbacks2;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

/*
http://android-er.blogspot.com/
Example to use onTrimMemory()
 */
public class MainActivity extends AppCompatActivity
        implements ComponentCallbacks2 {

    private static final String TAG = "MyActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.v(TAG, "onCreate() called");
    }

    public void onTrimMemory(int level){
        Log.v(TAG, "onTrimMemory(" + level + ")");
        switch(level){

            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
                Log.v(TAG, "TRIM_MEMORY_UI_HIDDEN");
                break;
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
                Log.v(TAG, "TRIM_MEMORY_RUNNING_MODERATE");
                break;
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
                Log.v(TAG, "TRIM_MEMORY_RUNNING_LOW");
                break;
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
                Log.v(TAG, "TRIM_MEMORY_RUNNING_CRITICA");
                break;
            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
                Log.v(TAG, "TRIM_MEMORY_BACKGROUND");
                break;
            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
                Log.v(TAG, "TRIM_MEMORY_MODERATE");
                break;
            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                Log.v(TAG, "TRIM_MEMORY_COMPLETE");
                break;

            default:
                Log.v(TAG, "default");
        }
    }

}


To simulate the memory low condition, you can use the adb command:

adb shell am send-trim-memory

Example for my case, it's:

adb shell am send-trim-memory com.blogspot.android_er.androidontrimmemory MODERATE

Notice that you cannot set background level if your app is in foreground. Otherwise the following exception will be thrown, as shown in the video.

java.lang.IllegalArgumentException: Unable to set a background trim level on a foreground process



reference:
Overview of memory management
Manage your app's memory





No comments: