What is a memory leak?
The root search algorithm is used for garbage collection of Android virtual machines. The GC will traverse the heap starting from the root node (GC Roots). In the end, some of the garbage that is not directly or indirectly referenced to GC roots is reclaimed by GC. A memory leak is a process in which some objects (garbage objects) are no longer useful, but they can be referenced directly or indirectly to GC roots resulting in the inability to be recycled by GC. Useless objects occupy memory space, resulting in the inability to reclaim the memory occupied by this object in a timely manner. When memory leaks accumulate beyond the Dalvik heap size, oom (OutOfMemory) occurs.
Classic scenes of memory leaks static instances of non-static inner classes
Because the inner class holds a reference to an external class by default, the static instance belongs to the class. Therefore, when an external class is destroyed, the inner class still holds a reference to the external class, causing the outer class to not be recycled by the GC. Thus causing a memory leak.
Give me a chestnut.
private static Leak mLeak; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); mLeak = new Leak(); } class Leak { }
Error chestnut Description: The static
keyword Modifier mLeak
property, which will mLeak
exist in the static zone, and Leak
as an inner class, holds a reference to the external class by default. When Activity
destroyed, mLeak
tightly hug Activity
thigh affectionate confession: "mlgb! Labor is not let you go!" ”。 Bucket mLeak
is not the property of the GC, naturally do not dare to recycle second-hand chicks Activity
. Thus causing a memory leak.
Incorrect handler
Error code example:
private MyHandler mMyHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); mMyHandler = new MyHandler(); mMyHandler.sendMessageDelayed(new Message(), 10 * 1000); } class MyHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }
The correct wording is as follows:
private MyHandler mMyHandler; static class MyHandler extends Handler { WeakReference<Activity> mActivityWeak; MyHandler(Activity act) { mActivityWeak = new WeakReference<Activity>(act); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (mActivityWeak.get() != null) { // doSomething } } }
We know handler.sendMessage(msg)
when, msg.target
will point handler
to, msg
will insert MessageQueue
. This is the basis for the following explanation, this part of the students who are not familiar with this blog can refer to.
The wrong place
MyHandler is an inner class that holds a reference to an external class by default. Activity
If MessageQueue
There are still unhandled messages in the destroy, the mMyHandler
example will continue to exist. While mMyHandler
holding Activity
the reference. Activity
cannot be recycled by GC.
Correct parsing
static
Keyword to decorate the MyHandler
class so that MyHandler does not hold references to external classes. Use WeakReference<activity>
guarantees when
activity
After destruction, the memory space occupied by GC reclamation is not delayed and activity
can be referenced before being destroyed activity
.
It's right to make it right.
From the above analysis, it can be concluded that handler caused the memory leak, because MessageQueue
there is still to be processed Message
, then we have to Activity#onDestroy()
remove all the messages are not finished. Anyway Activity
destroyed, MessageQueue
in the meaning of msg
what exists, can be removed. The code is as follows:
@Override protected void onDestroy() { super.onDestroy(); // 移除所有的callback和msg mMyHandler.removeCallbacksAndMessages(null); }
Static variables cause memory leaks
Here is an example of a context leak caused by a singleton pattern
public class Singleton { private static Singleton instance; private Singleton(Context context){ } public static Singleton getInstance(Context context){ if (instance == null){ synchronized (Singleton.class){ if (instance == null){ instance = new Singleton(context); } } } return instance; }}
The wrong place
In the calling Singleton#getInstance()
method if it is passed in Activity
. If instance
not released, then this Activity
will always exist. Thus causing a memory leak.
Repair Genuine
It will be new Singleton(context)
changed new Singleton(context.getApplicationContext())
so that it Activity
has no relation with the incoming. The release of the release, the home home.
Break it up and read
Cursor
File
Socket
buffers are often used when resources are used, and so on. You should close them in time when they are not needed and reclaim the amount of memory they occupy.
Bitmap
Don't recycle
drop it. Note that recycle
after the call does not mean immediately recycle
, just tell the virtual machine: Boy, it's time to work!
ListView
Be sure to use ConvertView
andViewHolder
BraodcastReceiver
Registration is done, you need to reverse registration
Memory Leak Detection Heap tool
- Open DDMS View
- Select a specific application under devices
- Select the second little green dot update Heap under devices
- Keep running the program and click Cause GC
- Follow the data object row, toal size column
- Play with your app and if you find toal size getting bigger and larger, there's probably a memory leak happening
The MAT (Memory Analyzer tool) tools export. hprof file
- Open DDMS View
- Select a specific application under devices
- Select the second little green dot update Heap under devices
- Click Cause GC
- Click Dump HPROF File
- Switch to the Mat page card, as shown by default
The most conspicuous is the pie chart, which lists the size of each type of data. And the Red Arrow refers to the dominator of a spell, however this does not have any eggs. Our focus is on the histogram. Don't say anything, click on it. The default diagram is as follows
The default is sort by class, and the first line supports regular expressions. For easy viewing, we'll group by the group by package. The right way to open it should be like this.
Memory Leak Demo
Here is a static instance of the non-static inner class, for example, the demo has only two activity, MainActivity
only one button, click Jump to SecondActivity
.
public class SecondActivity extends Activity { private static Leak mLeak; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); mLeak = new Leak(); } class Leak { }}
Find memory leaks
Launch the app, click Enter SecondActivity
, then press the Back button to return to MainActivity
. Open the .hprof
file. Look for our package name com.dyk.memoryleak
.
As you can see, although we are finished SecondActivity
, but SecondActivity
still exist, memory leaks no doubt.
1. Right SecondActivity
-click, select- List Objects
with incoming references
Results such as:
2. Right com.dyk.memoryleak.SecondActivity
-click, select- Path to GC
with all references
Results such as:
You can see that the reference to the Mleak property is causing the SecondActivity
collection to fail. Now that we have found the cause of the memory leak, I believe it is not very difficult to change it by the above introduction.
3. Enter again SecondActivity
. Since the last creation has SecondActivity
not yet been reclaimed, you can expect that there should be two instances at this time SecondActivity
.
The contents of the memory leak are over for the time being. Mat For more features, please find your own learning. Thanks for the patience to read the last ~
Introduction to Android memory leaks, typical scenarios, and detection solutions