Leakcanary
Android and Java memory leak detection.
"A small leak would sink a great ship." -Benjamin Franklin
Dikes, destroyed in the nest. --"Han Fei zi and Shang"
Demo
A very simple leakcanary demo:https://github.com/liaohuqiu/leakcanary-demo.
Start using
In build.gradle addition to the references, different compilations use different references:
dependencies { debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.3‘ releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.3‘ }
In the Application :
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); }}
So, everything is ready! In debug build, if a memory leak is detected for an activity, Leakcanary is automatically displayed with a notification.
Why do I need to use leakcanary?
Well, look at this article. Leakcanary: Let the memory leak no hiding
How to use
Use RefWatcher to monitor those objects that should be recycled.
RefWatcher refWatcher = {...};// 监控refWatcher.watch(schrodingerCat);
LeakCanary.install()will return a predefined activity that is RefWatcher also enabled ActivityRefWatcher for automatic monitoring after a call is Activity.onDestroy() released.
PublicClassExampleapplicationExtendsApplication{PublicStaticRefwatcherGetrefwatcher(ContextContext){ExampleapplicationApplication=(Exampleapplication)context. (); return application. Refwatcher} private refwatcher refwatcher @Override public void oncreate () {super. Oncreate (); refwatcher = leakcanary. Install (this} /span>
Using RefWatcher monitoring Fragment:
Publicabstract class basefragment extends fragment { @Override public ondestroy () {super.ondestroy (); refwatcher refwatcher = exampleapplicationgetrefwatcher (getactivity ()); refwatcher. (this} /span>
working mechanism
-
RefWatcher.watch()Create a keyedweakreference to the object to be monitored.
-
Then the background thread checks if the reference is cleared, and if not, the GC is called.
-
If the reference is still not cleared, dump the heap memory into a file in the APP's file system .hprof .
-
There is one in another process that HeapAnalyzerService HeapAnalyzer uses haha to parse this file.
-
Thanks to the unique reference key, HeapAnalyzer locate KeyedWeakReference and locate the memory leak.
-
HeapAnalyzerCalculates the shortest strong reference path to the GC roots and determines whether it is a leak. If so, establish a chain of references that leads to leaks.
-
The reference chain is passed into the APP process and is displayed in the DisplayLeakService form of notifications.
How do I copy leak trace?
In Logcat, you can see a leak trace like this:
In com.example.leakcanary:1.0:1 com.example.leakcanary.MainActivity has leaked:* GC ROOT thread java.lang.Thread.<Java Local> (named ‘AsyncTask #1‘)* references com.example.leakcanary.MainActivity$3.this$0 (anonymous class extends android.os.AsyncTask)* leaks com.example.leakcanary.MainActivity instance* Reference Key: e71f3bf5-d786-4145-8539-584afaecad1d* Device: Genymotion generic Google Nexus 6 - 5.1.0 - API 22 - 1440x2560 vbox86p* Android Version: 5.1 API: 22* Durations: watch=5086ms, gc=110ms, heap dump=435ms, analysis=2086ms
You can even share these things through the share button.
Memory leaks due to SDK
Over time, memory leaks in many SDK and vendor ROMs have been fixed as quickly as possible. However, when such a problem occurs, the average developer can do very limited things.
Leakcanary has a list of known issues, Androidexcludedrefs.java, if you find a new problem, please mention a issue and attach leak trace, reference key, machine model and SDK version. It would be nice if you could have a link to the dump file.
This is especially important for the latest release of Android. You have the opportunity to help early detection of new memory leaks, which can be of great benefit to the entire Android community.
The development version of the snapshots package is here: Sonatype ' s snapshots repository.
Outside of Leak trace
Sometimes, leak trace is not enough, you need to dig deep into the dump file through MAT or Yourkit.
You can find the problem in the following ways:
- Find all the
com.squareup.leakcanary.KeyedWeakReference instances.
- Check
key fields
- Find The that is
KeyedWeakReference a key field equal to the reference key reported by Leakcanary.
- The key is found with the same key value as the Logcat output
KeyedWeakReference .
referentThe field corresponds to the leaked object.
- All that remains is to fix it. It is best to check the shortest strong reference path to GC root to start.
customizing UI Styles
DisplayLeakActivityWith a default icon and tag, you can simply replace the following resources in your own APP resource.
res/ drawable-hdpi/ __leak_canary_icon.png drawable-mdpi/ __leak_canary_icon.png drawable-xhdpi/ __leak_canary_icon.png drawable-xxhdpi/ __leak_canary_icon.png drawable-xxxhdpi/ __leak_canary_icon.png
<?xml version="1.0" encoding="utf-8"?><resources> <string name="__leak_canary_display_activity_label">MyLeaks</string></resources>
Save Leak Trace
DisplayLeakActivitySaves up to 7 heap dumps & leak traces in the app directory. You can change this number by providing in R.integer.__leak_canary_max_stored_leaks your app:
In the APP's directory, DisplayLeakActivity 7 dump files and leak trace are saved. You can override the default value of the class library in your APP, defined R.integer.__leak_canary_max_stored_leaks .
<?xml version="1.0" encoding="utf-8"?><resources> <integer name="__leak_canary_max_stored_leaks">20</integer></resources>
Upload leak trace to server
You can change the default behavior for processing to complete and upload leak trace and heap dump to your server for statistical analysis.
To create one LeakUploadService , the simplest is to inherit DisplayLeakService :
PublicClassLeakuploadserviceExtendsDisplayleakservice{@OverrideProtectedvoidAfterdefaulthandling(Heapdumpheapdumpanalysisresult resultstring leakinfo) {if (! Result.| | result.{return} myserver. (heapdump. Heapdumpfileleakinfo} /span>
Please confirm release version using RefWatcher.DISABLED :
PublicClassExampleapplicationExtendsApplication{PublicStaticRefwatcherGetrefwatcher(ContextContext){ExampleapplicationApplication=(Exampleapplication)Context.Getapplicationcontext();ReturnApplication.refwatcher} private refwatcher refwatcher @Override public void oncreate () {super. Oncreate (); refwatcher = installleakcanary (); } protected refwatcher installleakcanary () {return refwatcher. Disabled} /span>
Custom RefWatcher :
public class DebugExampleApplication extends ExampleApplication { protected RefWatcher installLeakCanary() { return LeakCanary.install(app, LeakUploadService.class); }}
Don't forget to sign up for service:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" > <application android:name="com.example.DebugExampleApplication"> <service android:name="com.example.LeakUploadService" /> </application></manifest>
Android Memory leak analysis tool--leakcanary