Use Android studio to Analyze memory leakage
Use Android studio to Analyze memory leakage
This post is a permitted translation of badoo Tech Blog and I add some text and screenshots for android studio users.
Origin Author: Dmytro Voronkevych
Follow badoo on Tweet
Translator: Miao1007
As of androidstudio1.3, its internal MemoryDump functions are difficult to use, and MAT is better.
Android uses java for platform development, which helps us solve many underlying problems, such as memory management and platform dependency. However, we often encounterOutOfMemoey
Q: Where is garbage collection?
Next isHandler Leak
In the compiler.
Sample Code of the required tool Android Studio 1.1 or higher Eclipse MemoryAnalyzer
public class NonStaticNestedClassLeakActivity extends ActionBarActivity { TextView textView; public static final String TAG = NonStaticNestedClassLeakActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_non_static_nested_class_leak); textView = (TextView)findViewById(R.id.textview); Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void textView.setText(Done); }//a mock for long time work }, 800000L); }}
This is a very basic Activity. Pay attention to this anonymousRunnable
It is sent to Handler, and the delay is very long. Now we run this Activity, rotate the Screen repeatedly, export the memory and analyze it.
Import Memory to Eclipse MemoryAnalyzer and use Androidstudio to export heap dump
Android Studio dump Memory Analyze click Android in the lower left corner to select the package name of your program. Click initiates garbage collection on selected vm and click dump java heap for selected client to open MAT for analysis.
MAT is a tool for analyzing variables in java heap. It can be used to analyze memory leaks.
Click
OQL
Enter the icon in the window
select * from instanceof android.app.Activity
And press
Ctrl + F5
Or
!
The button miracle appeared, and now you find that many activity leaks are really not optimistic. Let's analyze why GC didn't recycle it.
EMA
The input Query command in the OQL (Object Query Language) window can obtain all the Activities in the memory. Is this Query code very simple and efficient?
Right-click an activity object and selectPath to GC roots
GC root
Message in loginhold a reference to Activity
In the new window, you can find that your Activity isthis$0
It is actually an anonymous class reference to the current class.this$0
Andcallback
Then it is referencedMessage
A stringnext
Referenced by the primary thread.
In any case, when you create a non-static internal class in the class, the internal class will (automatically) have a strong reference to the current class.
Once youRunnable
OrMessage
SendHandler
, It will be placed inLooperThread
And is referencedMessage
Processed. If a message such as postDelayed is sent, the message will be leaked for at least several seconds after you enter the delay. If a message without delay is sent, a temporary leak occurs when too many messages are in the queue.
Try to use static inner class
NowRunnable
Change to static class
StaticClass
Now, shake your phone and export the memory.
StaticClass_memory_analyze
Why did another leak occur? Let's take a lookActivities
.
StaticClass_memory_analyze_explained
See the followingmContext
Is it referencedmTextView
Reference, which means that using static internal classes is far from enough, and we still need to modify them.
Use Weak reference + static Runnable
Now let's change TextView, the culprit of Memory leakage, to weak reference.
StaticClassWithWeakRef_code
Note that what we keep for TextView isWeak referenceNow let it run and shake the phone
Operate WeakReferences with caution. They can be empty at any time. Before use, you must determine whether it is empty.
StaticClassWithWeakRef_memory_analyze
Wow! Now there is only one Activity instance, and this has finally solved our problem.
Therefore, we should remember:
Weak references are required for Handler/Runnable dependency of static internal classes.
If you compare the current code with the start code, you will find that they are very different, the start code is easy to understand, and you can even come up with the running results.
The current Code is more complex and there are a lot of template code.postDelayed
Set to a short time, such50ms
In this case, writing so much code is a bit of a loss. In fact, there is a simpler method.
Manually control the claim period in onDestroy
Handler can useremoveCallbacksAndMessages(null)
It will removeRunnable
AndMessage
.
//Fixed by manually control lifecycle @Override protected void onDestroy() { super.onDestroy(); myHandler.removeCallbacksAndMessages(null); }
Run now, rotate the phone, and export the memory
RemoveCallbacks_memory_analyze
Good! There is only one instance.
In this way, your code can be more concise and readable. The only thing to remember is to manually remove all messages during the onDestory lifecycle.
Use WeakHander
(This is a third-party library, so I will not translate it. Go to Github to learn it)
Conclusion
Use in HandlerpostDelayed
Note that there are three methods to solve the problem.
When using static internal Handler/Runnable + weak reference in onDestory, manually clear the Message using third-party WeakHandler developed by Badoo
You can choose either of the three options. The second option looks more reasonable, but requires additional work. The third method is my favorite. Of course, you must note that WeakHandler cannot be used together with external strong references.