Android performance optimization - memory leak

Posted by MobiTec on Tue, 09 Jul 2019 19:15:07 +0200

Reload address: http://www.jianshu.com/p/402225fce4b2

JVM Memory Management

Java uses GC for memory management.An in-depth knowledge of JVM memory management is recommended, Understanding Java Virtual Machines in depth.As for memory leaks, there are several strategies for memory allocation in JVM.

  • Static

Static memory, which is allocated at the time the program is compiled, persists throughout the program's run. It stores static data, global static data, and some constants.

  • Stacked

When a method is executed, the storage of some internal variables of the method can be created on the stack, and these storage units are automatically commented out when the method is executed.Stack memory includes allocations that run fast because they are built into the processor.Of course, the capacity is limited, and a stack of contiguous memory area, the size is determined by the operating system, he goes in and out, complete without fragmentation, efficient and stable operation

  • Heap

Also known as dynamic memory.We usually use new to request a memory allocation.This is also the key storage where we discuss memory leak optimization.GC reclaims the garbage memory in the heap memory based on memory usage.Heap memory is a discontinuous area of memory. Frequent new/remove can cause a lot of memory fragmentation, frequent GC recycling can cause memory jitter, which can also consume the performance of our applications.

We know we can call System.gc(); do memory recycling, but GC may not necessarily execute.Is there anything we can do about the GC mechanism?In fact, we can make GC recycle memory better by declaring some reference tags.

  • StrongReference The GC cannot recycle him at any time, even if memory is low, the system will throw an exception OutOfMemoryError directly and the recycling process will not terminate
  • SoftReference does not reclaim objects of this type of reference when there is enough memory, only when there is not enough memory to reclaim, when GC is in progress
  • WeakReference GC runs and terminates after GC is recycled
  • PhantomReference If an object is associated with a virtual reference, it is possible to be recycled by the garbage collector at any time, just as there is no reference associated with it
    In order to prevent memory overflow during development, soft and weak references can be used whenever possible when dealing with objects that are memory-intensive and have a long life cycle.

Tip

  • Member variables are all stored in the heap (including basic data types, referenced object entities) because they belong to classes, and class objects are ultimately to be new er

  • Basic data types and references to local variables exist on the stack, and the applied object entities are stored on the stack.Because they are variables in a method, the lifecycle ends with the method

Definition of memory leak

When an object is no longer needed and should have been recycled, another object in use holds its reference, which prevents the object from being recycled by the GC.This causes the object that should have been recycled to remain in heap memory instead of being recycled, resulting in a memory leak

Difference between memory leak and memory overflow

  • Memory Leak
    Some objects in the process are no longer of use value, but they can also be referenced directly or indirectly to the GC Root leading to non-recyclability.When there are too many memory leaks, combined with the memory used by the application itself, cumulative memory overflow eventually results in OOM

  • Memory Overflow (OOM)
    Memory overflow occurs when the heap resource of the application exceeds the memory allocated by the Dalvik virtual machine

The impact of memory leaks

  • Apply Carton
    Leaked memory affects GC memory allocation, too many memory leaks affect application execution efficiency

  • Apply Exception (OOM)
    Too many memory leaks will eventually cause Dalvik to allocate memory for OOM

Common memory leaks in Android development

Memory leak caused by a single case

  • Error example

When getInstance is called, if the context passed in is the context of the Activity.As long as this case is not released, then this
Activity will not be released until the process exits.

public class CommUtil {
    private static CommUtil instance;
    private Context context;
    private CommUtil(Context context){
    this.context = context;
    }

    public static CommUtil getInstance(Context mcontext){
    if(instance == null){
        instance = new CommUtil(mcontext);
    }
    return instance;
    }
  • Solution

Instead of using Activity's Content when you can use Application's Context, the life cycle of the Application follows the cycle of the entire process

Memory leak caused by static instance creation by a non-static internal class

  • Error example
 private static TestResource mResource = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(mManager == null){
            mManager = new TestResource();
        }

    }
    class TestResource {

    }
  • Solution

Modify a non-static internal class to a static internal class.(Static internal classes do not implicitly hold external classes)

Memory leak caused by Handler

  • Error example

MHandler is an instance of Handler's non-static, anonymous internal class, so it holds a reference to the external class Activity. We know that Message queuing is constantly polling for messages in a Looper thread. When this activity exits, there are still unprocessed messages in the Message queue or messages being processed, while M in the Message queueEssage holds a reference to an instance of mHandler, and mHandler holds a reference to an activity. As a result, the activity's memory resources cannot be recycled in a timely manner, causing a memory leak.

    private MyHandler mHandler = new MyHandler(this);
    private TextView mTextView ;
    private static class MyHandler extends Handler {
        private WeakReference<Context> reference;
        public MyHandler(Context context) {
            reference = new WeakReference<>(context);
        }
        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = (MainActivity) reference.get();
            if(activity != null){
                activity.mTextView.setText("");
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView)findViewById(R.id.textview);
        loadData();
    }

    private void loadData() {

        Message message = Message.obtain();
        mHandler.sendMessage(message);
    }
  • Solution

Create a static Handler internal class and then use weak references to the objects held by the Handler so that the objects held by the Handler can also be recycled on recycle, which avoids activity leaks, but there may still be messages to be processed in the message queue of the Looper thread, so when we are in Activity's Dextroy, or Stop should remove messages from the message queue

    private MyHandler mHandler = new MyHandler(this);
    private TextView mTextView ;
    private static class MyHandler extends Handler {
        private WeakReference<Context> reference;
        public MyHandler(Context context) {
            reference = new WeakReference<>(context);
        }
        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = (MainActivity) reference.get();
            if(activity != null){
                activity.mTextView.setText("");
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView)findViewById(R.id.textview);
        loadData();
    }

    private void loadData() {
        //...request
        Message message = Message.obtain();
        mHandler.sendMessage(message);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }
}

Memory leak caused by thread

  • Error example

Asynchronous tasks and Runnable s are both anonymous internal classes, so they have an implicit reference to the current Activity.If the task is not completed before the Activity is destroyed, it will cause the Activity's memory resources to not be reclaimed, causing a memory leak

    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            SystemClock.sleep(10000);
            return null;
        }
    }.execute();


    new Thread(new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(10000);
        }
    }).start();
  • Solution

Static internal classes are used to avoid memory resource leaks from the Activity. Of course, the corresponding task AsyncTask::cancel() should be canceled when the Activity is destroyed to avoid wasting resources when the task is executed in the background.

   static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        private WeakReference<Context> weakReference;

        public MyAsyncTask(Context context) {
            weakReference = new WeakReference<>(context);
        }

        @Override
        protected Void doInBackground(Void... params) {
            SystemClock.sleep(10000);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            MainActivity activity = (MainActivity) weakReference.get();
            if (activity != null) {
                //...
            }
        }
    }
    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            SystemClock.sleep(10000);
        }
    }

    new Thread(new MyRunnable()).start();
    new MyAsyncTask(this).execute();

Memory leak caused by resource not closing

  • Error example

Use of resources such as BraodcastReceiver, ContentObserver, File, Cursor, Stream, Bitmap should be closed or logged off in time when the Activity is destroyed, otherwise these resources will not be recycled, causing a memory leak

  • Solution

    Close or log off Activity in time when it is destroyed

Use static Activity and View

  • Error example
static view; 

    void setStaticView() { 
      view = findViewById(R.id.sv_button); 
    } 

    View svButton = findViewById(R.id.sv_button); 
    svButton.setOnClickListener(new View.OnClickListener() { 
      @Override public void onClick(View v) { 
        setStaticView(); 
        nextActivity(); 
      } 
    }); 


    static Activity activity; 

    void setStaticActivity() { 
      activity = this; 
    } 

    View saButton = findViewById(R.id.sa_button); 
    saButton.setOnClickListener(new View.OnClickListener() { 
      @Override public void onClick(View v) { 
        setStaticActivity(); 
        nextActivity(); 
      } 
    });
  • Solution

Static applications should be null in time, and View and Activity are generally not recommended to be static

System services registered, but onDestory is not unregistered

  • Error example
SensorManager sensorManager = getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
sensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);

- Solutions

//Remove monitoring when not needed
 sensorManager.unregisterListener(listener);

Memory leaks occur if unneeded listeners are not removed

  • Error example
//add listen, put in collection
    tv.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
        @Override
        public void onWindowFocusChanged(boolean b) {
            //Listens for the view to load, and calculates its width and height when the view loads.
        }
    });
  • Solution
//Be sure to remove this monitor after calculation
tv.getViewTreeObserver().removeOnWindowFocusChangeListener(this);

//Tip

tv.setOnClickListener();//Listen for recycled objects without regard to memory leaks
tv.getViewTreeObserver().addOnWindowFocusChangeListene,addListen, put into collection, need to consider memory leak

Topics: jvm Java Android