Android memory leak and memory overflow solution (summary)

Memory overflow out of memory means that when the program applies for memory, there is not enough memory space for it to use, and out of memory occurs; for example, if an integer is applied for, but the number that can be stored by long is stored for it, that is memory overflow .

Reasons:
1. The amount of data loaded in the memory is too large, such as taking too much data from the database at one time;
2. There are references to objects in the collection class, which are not emptied after use, so that the JVM cannot be recycled;
3. There is a deadlock in the code The cycle or cycle generates too many repeated object entities;
4. BUG in the third-party software used;
5. The startup parameter memory value is set too small

Memory leak memory leak means that the program cannot release the memory space that has been applied after applying for memory. The harm of a memory leak can be ignored, but the accumulation of memory leaks has serious consequences. No matter how much memory, it will be occupied sooner or later.

A memory leak will eventually lead to a memory overflow! Everyone knows that the virtual machine will allocate a certain amount of memory for each application. When your request volume exceeds this value, it is a memory overflow.

Memory leak solution:

Memory leak caused by static variables (solution: reset the static variable to null at an appropriate time, so that it no longer holds a reference, which can also avoid memory leakage. For example, static context, static view; static variables are stored in Method area, its life cycle starts from class loading to the end of the entire process. Once the static variable is initialized, the reference it holds will not be released until the process ends)

Static singleton mode holds Activity or services that cannot be released (solution: refer to the global context singleton mode corresponds to the life cycle of the application, so we try to avoid using the Activity context when constructing a singleton, but use the Application's context. context)

Non-static inner class causes memory leak (case 1) (for example: Handler, non-static inner class (including anonymous inner class) will hold the reference of the outer class by default, when the life cycle of the non-static inner class object is longer than that of the outer class object When the life cycle is long, it will lead to memory leakage.
mHandler will be saved as a member variable in the sent message msg, that is, msg holds the reference of mHandler, and mHandler is a non-static inner class instance of Activity, that is, mHandler holds the reference of Activity , then we can understand that msg indirectly holds a reference to Activity. After msg is sent, it is first placed in the message queue MessageQueue, and then waiting for Looper's polling processing (MessageQueue and Looper are both associated with threads, and MessageQueue is Looper reference The member variable of , and Looper is stored in ThreadLocal). Then when the Activity exits, msg may still exist in the message queue MessageQueue that has not been processed or is being processed, which will cause the Activity to not be recycled, resulting in the occurrence of Activity's Memory leak.
Solution:
Usually in Android development, if you want to use inner classes, but you want to avoid memory leaks, you generally use static inner classes + weak references. (When GC performs garbage collection, it will be recycled when it encounters Activity and release the occupied memory unit), but msg may still exist in the message queue MessageQueue, so it is better to remove the callback of mHandler and the message sent when the Activity is destroyed.

public class MainActivity extends AppCompatActivity {

    private Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler = new MyHandler(this);
        start();
    }

    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }

    private static class MyHandler extends Handler {

        private WeakReference<MainActivity> activityWeakReference;

        public MyHandler(MainActivity activity) {
            activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = activityWeakReference.get();
            if (activity != null) {
                if (msg.what == 1) {
                    // 做相应逻辑
                }
            }
        }
    }
}

Non-static inner classes cause memory leaks (case 2)
Non-static inner classes cause memory leaks. Another situation is to use Thread or AsyncTask
, such as directly creating a new sub-thread Thread in Activity: (newThread new Runable method; newly created sub-threads Thread and AsyncTask is an anonymous inner class object, which implicitly holds a reference to an external Activity by default, resulting in Activity memory leak. To avoid memory leak, you still need to use the static inner class + weak application method like the Handler above (the code is not listed). , refer to the correct spelling of Hanlder above).)

Memory leaks caused by unregistration or callbacks
. For example, if we register the broadcast in the Activity, if we do not cancel the registration after the Activity is destroyed, the just broadcast will always exist in the system, holding the Activity reference like the non-static inner class mentioned above. lead to memory leaks. Therefore, after registering the broadcast, you must cancel the registration after the Activity is destroyed.
For example, if we register the broadcast in the Activity, if the registration is not cancelled after the Activity is destroyed, then the just broadcast will always exist in the system, and the same as the non-static inner class mentioned above, it will hold the Activity reference, resulting in memory leaks. Therefore, after registering the broadcast, you must cancel the registration after the Activity is destroyed.

Timer and TimerTask cause memory leaks
Timer and TimerTask are usually used in Android to do some timing or cyclic tasks, such as ViewPager that implements infinite carousel:
When our Activity is destroyed, it is possible that Timer is still waiting to execute TimerTask, which The reference held by the Activity cannot be recycled, so when our Activity is destroyed, we must immediately cancel the Timer and TimerTask to avoid memory leaks.

The objects in the collection are not cleaned up causing memory leaks
. This is easy to understand. If an object is put into a collection such as ArrayList, HashMap, etc., the collection will hold a reference to the object. When we no longer need the object, we don't remove it from the collection, so as long as the collection is still in use (and the object is useless), the object causes a memory leak. And if the collection is statically referenced, the useless objects in the collection will cause memory leaks. Therefore, when using the collection, it is necessary to remove the unused objects from the collection, or clear the collection in time to avoid memory leaks.

The resource is not closed or released, resulting in memory leak
. When using IO, File stream, or Sqlite, Cursor and other resources, it should be closed in time. These resources usually use buffers during read and write operations. If they are not closed in time, these buffer objects will always be occupied and not released, resulting in memory leaks. Therefore, we close them in time when we don't need to use them, so that the buffer can be released in time to avoid memory leaks.

Attribute animation (repeatCount is infinite mode) Thread optimization
animation is also a time-consuming task. For example, attribute animation (ObjectAnimator) is started in Activity, but when it is destroyed, the cancel method is not called. Although we can't see the animation, but This animation will still be played continuously. The animation refers to the control where the control is located, and the control refers to the Activity, which causes the Activity to be unable to be released normally. Therefore, it is also necessary to cancel the attribute animation when the Activity is destroyed to avoid memory leaks.

WebView causes memory leaks
About the memory leaks of WebView, because WebView will occupy memory for a long time after loading the web page and cannot be released, so we need to call its destroy() method after the Activity is destroyed to destroy it to release the memory.
In addition, I saw this situation when I looked up the relevant information on WebView memory leakage:
The Callback under Webview holds the Activity reference, which causes the Webview memory to be unable to be released. Even calling Webview.destory() and other methods cannot solve the problem (after Android 5.1) ).

The final solution is to remove the WebView from the parent container before destroying the WebView, and then destroy the WebView. For the detailed analysis process, please refer to this article: WebView Memory Leak Solution.

@Override
protected void onDestroy() {
    super.onDestroy();
    // 先从父控件中移除WebView
    mWebViewContainer.removeView(mWebView);
    mWebView.stopLoading();
    mWebView.getSettings().setJavaScriptEnabled(false);
    mWebView.clearHistory();
    mWebView.removeAllViews();
    mWebView.destroy();
}

LeakCanary is a fool-proof and visual memory leak analysis tool
. Principle: monitor an object that is about to be destroyed.
Vernacular : create a weak reference object for the monitored object, and the background thread checks whether the object is cleared. If not, it triggers garbage collection. If the weak reference object still exists after recycling, it means that a memory leak has occurred
1. The RefWatcher.watch() function will create a KeyedWeakReference weak reference object for the monitored object, which is a subclass of WeakReference pair and adds key-value pair information. The weak reference object will be found later according to the specified key key;
2. In the background thread AndroidWatchExecutor, check whether the KeyedWeakReference weak reference has been cleared. If it still exists, after triggering a garbage collection. After garbage collection, if the weak reference object still exists, it means that a memory leak has occurred;

Memory leaks are an important aspect of Android memory optimization. Many times memory leaks occur in programs, and we may not notice them. All in the process of coding, we must develop good habits. Try not to use Activity when
constructing singletons. When making
static references, pay attention to emptying application objects or use less static references;
use static inner classes + soft references instead of non-static inner classes;
cancel broadcasting or observer registration in time;
remember time-consuming tasks and attribute animations when Activity is destroyed cancel;
resources such as file stream and Cursor are closed in time;
WebView is removed and destroyed when Activity is destroyed.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325625187&siteId=291194637