Android tools: leakcanary-Memory Leak detection artifact

Source: Internet
Author: User

I. Introduction of Leakcanary
Leakcanary is a library of open-source detection memory leaks from square, which can easily integrate with your project and monitor memory leaks in the debug version of activity, fragment, etc.
After the leakcanary is integrated into the project, a message is sent to the system notification bar when a memory leak is detected. Click to open the name Displayleakactivity page, and display the leaked tracking information, Logcat above will also have the corresponding log output. At the same time, if the tracking information is not enough to locate, Displayleakactivity also saved the last 7 dump files to the app directory for the developer by default, and the dump file can be further analyzed using tools such as mat.
ii. Introduction to memory leaks
After understanding the Leakcanary access way, we must be anxious to see the power of leakcanary. Before you demonstrate leakcanary detection and processing composition, you should be aware of the memory leaks have a basic understanding and understanding;
1. Why does a memory leak occur?
When an object does not need to be recycled, there is another object in use that holds its reference, causing it to not be recycled in the heap memory, which creates a memory leak;
2. What is the impact of memory leaks on programs?
Memory leaks are one of the main causes of application Oom. The Android system allocates limited memory for each application, and when there is more memory leaks in the application, it is unavoidable that the memory required by the application exceeds the system allocation limit, which results in the crash of the Oom application.
3.Android common memory leaks?
believe that memory leaks to everyone has heard, but it is not like some Java anomalies, will immediately cause the crash of the program, but there are people to compare "unfamiliar." Below we list the common memory leakage types in daily development, so that people's understanding of memory leakage is not only in the "heard" level;
single case causes:Since the single-instance static characteristic makes the life cycle of the singleton as long as the life cycle of the application, if an object (such as the context) is no longer in use, and the singleton object still holds the object's reference, the object cannot be recycled properly;
creating a static instance of a non-static inner class causes:Create a non-static inner class singleton in acitivity memory to avoid re-creating the resource each time it is started. However, because a non-static inner class holds a reference to an external class (Activity) by default and uses that class to create a static instance. Causes the instance to be as long as the application life cycle, causes the static instance to hold the reference activity and the resource not to recycle normally;
handler causes:A child thread executes a network task and uses handler to process a child thread to send a message. Because the handler object is an object of a non-static anonymous inner class, a reference to the external class (Activity) is held. In Handler-message, Looper threads constantly poll for processing messages, and when activity exits with messages that are not processed or being processed, messages in Message Queuing hold handler object references, and handler also hold activity. The memory and resources that lead to activity cannot be recovered in time;
Threads Cause:Anonymous inner classes Runnalbe and Asynctask objects perform asynchronous tasks, implicitly referencing the current activity. When the activity is destroyed, the task is not finished, which will lead to the memory and resources of the activity can not be recovered in time;
memory leaks due to resource not shutting down:For use of resources such as Broadcastreceiver,contentobserver,file,cursor,stream,bitmap, should be closed or logged off when the activity is destroyed, otherwise these resources will not be recycled, cause a memory leak;
third, leakcanary access
Below we will also demonstrate how to access Leakcanary in the project with the Qproject project, the project directory is as follows:

1. Adding leakcanary dependencies
Add Leakcanary dependency in the main project main module's Build.gradle file;
/main/build.gradle file
Apply plugin: ' Com.android.application ' android {    ...  ...} dependencies {    ...    Add leakcanary dependent    //In release and test versions, using the No-op version of Leakcanary, which is the wrapper version without the actual code and operation, Contains only empty implementations of the Leakcanary and Refwatcher classes, which will not affect the generated APK package volume and application Performance    Debugcompile ' com.squareup.leakcanary: leakcanary-android:1.5 '    releasecompile ' com.squareup.leakcanary:leakcanary-android-no-op:1.5 '    Testcompile ' com.squareup.leakcanary:leakcanary-android-no-op:1.5 ' ...    Compile project (': Test ')}
2. Initialize Leakcanary
Initialize the leakcanary in the OnCreate () method of the main project main module qapplication.
/main/src/main/java/com/qproject/main/qapplication.java file
public class Qaplication extends application{    @Override public    void OnCreate () {        super.oncreate ();        ... ...        Initialize Leakcanary        if (leakcanary.isinanalyzerprocess (this)) {            return;        }        Leakcanary.install (this);}    }
OK, here we have completed a project of leankcanary simple access;
Tip 1: after integrating the leakcanary, the error is as follows when building and installing the APK:
Error:error converting bytecode to Dex:
Cause:com.android.dex.DexException:Multiple dex files define lcom/squareup/leakcanary/leakcanary;
Error:execution failed for task ': Main:transformclasseswithdexfordebug '.
> com.android.build.api.transform.TransformException:com.android.ide.common.process.ProcessException: Java.util.concurrent.ExecutionException:java.lang.UnsupportedOperationException
Process 1: add dependent debugcompile ' com.squareup.haha:haha:2.0.3 ', modify dependent version for 1.4-BETA2;
iv. detection of leakcanary
By learning about some of the common memory leaks, we've learned about memory leaks. So here's a leakcanary tool that lets you feel the real existence of it in your daily development. We use common memory-a single case of memory leakage as an example to practice;
1. Single Memory leak simulation
Test/src/main/com/qproject/test/testmanager.java
public class Testmanager {    //single-instance static characteristics make the life cycle of a singleton as long as the life cycle of the application    private static Testmanager instance;    Private context context;    /**     * The lifecycle of the incoming context is important:     * If the context of the   application is passed in, the life cycle is as long as the singleton life cycle;   If the context of the activity is passed in, because the context is as long as the activity's life cycle, its memory is not recycled when the activity exits because the Singleton object holds its reference;     */    private Testmanager (Context context) {        This.context = context;    }    public static Testmanager getinstance (context context) {        if (instance = = null) {            instance = new Testmanager (cont EXT);        }        return instance;}    }
Test/src/main/com/qproject/test/leakcanary/leakcanaryactivity.java
public class Leakcanaryactivity extends Appcompatactivity {    @Override    protected void OnCreate (Bundle Savedinstancestate) {        super.oncreate (savedinstancestate);        Setcontentview (r.layout.activity_leakcanary);        Get Singleton object, exit activity to simulate memory leak        Testmanager Testmanager = testmanager.getinstance (this);}    }
2. Detection Message Notification
Run the app to the Leakcanaryactivit page and exit and send a message to the system notification bar when a memory leak is detected;

3. View inspection Details
Click the notification message to open a page named displayleakactivity and display the leaked tracking information;

4. View Logcat logs
In addition to the above leakage information display, Logcat above will also have corresponding log output;
Memory Leak object com.qproject.test.leakcanary.leakcanaryactivity12-25 07:50:51.710 4941-5795/com.qproject.main D/ Leakcanary: * Com.qproject.test.leakcanary.LeakCanaryActivity has leaked://static The com.qproject.test.TestManager.instance com.qproject.test.TestManager.context references the recovered memory object 12-25 07:50:51.710 4941-5795/com.qproject.main d/leakcanary: * GC ROOT static com.qproject.test.testmanager.instance12-25 07:50:51.710 4941-5795/com.qproject.main d/leakcanary: * References com.qproject.test.testmanager.context//memory leak object size, Reference Key,device and Android version information 12-25 07:50:51.710 4941-5795/com.qproject.main d/leakcanary: * leaks Com.qproject.test.leakcanary.LeakCanaryActivity instance12-25 07:50:51.710 4941-5795/com.qproject.main d/ Leakcanary: * retaining:46 kb.12-25 07:50:51.710 4941-5795/com.qproject.main d/leakcanary: * Reference key:3d74d294-70d c-4447-a9a2-64e656ea86b812-25 07:50:51.710 4941-5795/com.qproject.main d/leakcanary: * device:genymotion Android Preview-google Nexus 5x-7.0.0-api 24 -1080x1920 vbox86p12-25 07:50:51.710 4941-5795/com.qproject.main d/leakcanary: * Android version:7.0 api:24 LeakCanary : 1.5 00f37f512-25 07:50:51.710 4941-5795/com.qproject.main d/leakcanary: * durations:watch=5038ms, gc=137ms, Heap dump= 2390MS, analysis=27325ms//memory leak object Details 12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: * details:12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: * Class com.qproject.test.testmanager12-25 07:50:51.711   4941-5795/com.qproject.main D/leakcanary: |   static instance = [email protected] (0x12d898f0) 12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: | Static $classOverhead = byte[308]@316175745 (0x12d87581) 12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: *   Instance of com.qproject.test.testmanager12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   static instance = [email protected] (0x12d898f0) 12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: | Static $classOverhead = byte[308]@316175745 (0x12d87581) 12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   context = [email protected] (0x12c76e00) 12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   Shadow$_klass_ = com.qproject.test.testmanager12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: | Shadow$_monitor_ = 012-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: * Instance of   com.qproject.test.leakcanary.leakcanaryactivity12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: | Static $classOverhead = byte[2228]@316203009 (0x12d8e001) 12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary:   |   Mdelegate = [email protected] (0x12d35e50) 12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: |   Meatkeyupevent = false12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   mresources = null12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: | Mthemeid = 213123088412-25 07:50:51.711 4941-5795/com.qproject.main d/leakCanary: |   mcreated = true12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   Mfragments = [email protected] (0x12d89420) 12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: |   Mhandler = [email protected] (0x12d84520) 12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: |   Mnextcandidaterequestindex = 012-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   moptionsmenuinvalidated = false12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: | Mpendingfragmentactivityresults = [email protected] (0x12d86850) 12-25 07:50:51.711 4941-5795/com.qproject.main   D/leakcanary: |   mreallystopped = true12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   Mrequestedpermissionsfromfragment = false12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: |   mresumed = false12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   mretaining = false12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: | Mstopped = true12-25 07:50:51.711 4941-5795/com.qproject.main d/leakcanary: |   Mstartedactivityfromfragment = false12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: |   Mstartedintentsenderfromfragment = false12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: |   Mextradatamap = [email protected] (0x12d86658) 12-25 07:50:51.711 4941-5795/com.qproject.main D/LeakCanary: |   Mactionbar = null12-25 07:50:51.712 4941-5795/com.qproject.main d/leakcanary: |   mactionmodetypestarting = 012-25 07:50:51.712 4941-5795/com.qproject.main d/leakcanary: |   Mactivityinfo = [email protected] (0x12d35dc0) 12-25 07:50:51.712 4941-5795/com.qproject.main D/LeakCanary: | Mactivitytransitionstate = [email protected] (0x12d8f0e8) 12-25 07:50:51.712 4941-5795/com.qproject.main D/   Leakcanary: |   Mapplication = [email protected] (0x12c53e40) 12-25 07:50:51.712 4941-5795/com.qproject.main D/LeakCanary: | mcalled = true12-25 07:50:51.712 4941-5795/com.qproject.main D/LEAKCANary: |   Mchangecanvastotranslucent = false12-25 07:50:51.712 4941-5795/com.qproject.main D/LeakCanary: |   Mchangingconfigurations = false12-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: |   Mcomponent = [email protected] (0x12d5c070) 12-25 07:50:51.713 4941-5795/com.qproject.main D/LeakCanary: |   Mconfigchangeflags = 012-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: |   Mcurrentconfig = [email protected] (0X12D881C8) 12-25 07:50:51.713 4941-5795/com.qproject.main D/LeakCanary: |   Mdecor = null12-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: |   Mdefaultkeymode = 012-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: |   MDEFAULTKEYSSB = null12-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: |   mdestroyed = true12-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: |   Mdoreportfullydrawn = false12-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: | Meatkeyupevent = false12-25 07:50:51.713 4941-5795/com.qProject.main D/leakcanary: |   Membeddedid = null12-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: |   Menabledefaultactionbarup = false12-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: | Mentertransitionlistener = android.app.sharedelementcall[email protected] (0x707a4a98) 12-25 07:50:51.713   4941-5795/com.qproject.main D/leakcanary: | Mexittransitionlistener = [email protected] (0x707a4a98) 12-25 07:50:51.713 4941-5795/com.qproject.main D/   Leakcanary: |   mfinished = true12-25 07:50:51.713 4941-5795/com.qproject.main d/leakcanary: |   Mfragments = [email protected] (0x12d893f0) 12-25 07:50:51.713 4941-5795/com.qproject.main D/LeakCanary: |   Mhandler = [email protected] (0X12D844E0) 12-25 07:50:51.714 4941-5795/com.qproject.main D/LeakCanary: |   Mhascurrentpermissionsrequest = false12-25 07:50:51.714 4941-5795/com.qproject.main D/LeakCanary: |   Mident = 2035664012-25 07:50:51.714 4941-5795/com.qproject.main d/leakcanary: | Minstancetracker= [email protected] (0x12d89400) 12-25 07:50:51.714 4941-5795/com.qproject.main d/leakcanary: |   Minstrumentation = [email protected] (0x12c5c3e8) 12-25 07:50:51.714 4941-5795/com.qproject.main D/LeakCanary: |   Mintent = [email protected] (0x12d91078) 12-25 07:50:51.714 4941-5795/com.qproject.main D/LeakCanary: |   mlastnonconfigurationinstances = null12-25 07:50:51.714 4941-5795/com.qproject.main D/LeakCanary: |   Mmainthread = [email protected] (0x12c60100) 12-25 07:50:51.715 4941-5795/com.qproject.main D/LeakCanary: |   Mmanagedcursors = [email protected] (0x12d86628) 12-25 07:50:51.715 4941-5795/com.qproject.main D/LeakCanary: |   Mmanageddialogs = null12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mmenuinflater = null12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mparent = null12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: | Mreferrer = [email protected] (0x12d91238) 12-25 07:50:51.715 4941-5795/com.qproJect.main D/leakcanary: |   Mresultcode = 012-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mresultdata = null12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   mresumed = false12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Msearchevent = null12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Msearchmanager = null12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   mstartedactivity = false12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   mstopped = true12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mtaskdescription = [email protected] (0x12d84500) 12-25 07:50:51.715 4941-5795/com.qproject.main D/LeakCanary: |   Mtemporarypause = false12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mtitle = [email protected] (0X12C87FE0) 12-25 07:50:51.715 4941-5795/com.qproject.main D/LeakCanary: | Mtitlecolor = 012-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanarY: |   Mtitleready = true12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mtoken = [email protected] (0x12d3c0c0) 12-25 07:50:51.715 4941-5795/com.qproject.main D/LeakCanary: |   Mtranslucentcallback = null12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Muithread = [email protected] (0x74cf7000) 12-25 07:50:51.715 4941-5795/com.qproject.main D/LeakCanary: |   Mvisiblebehind = false12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mvisiblefromclient = true12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mvisiblefromserver = true12-25 07:50:51.715 4941-5795/com.qproject.main d/leakcanary: |   Mvoiceinteractor = null12-25 07:50:51.716 4941-5795/com.qproject.main d/leakcanary: |   Mwindow = [email protected] (0X12C84D40) 12-25 07:50:51.717 4941-5795/com.qproject.main D/LeakCanary: |   mwindowadded = true12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Mwindowmanager = [email protected] (0x12d86778) 12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Minflater = com.android.internal.policy.pho[email protected] (0x12d5ef70) 12-25 07:50:51.717 4941-5795/   Com.qproject.main D/leakcanary: |   Moverrideconfiguration = null12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: |   Mresources = [email protected] (0X12D960D8) 12-25 07:50:51.717 4941-5795/com.qproject.main D/LeakCanary: |   Mtheme = [email protected] (0x12d894b0) 12-25 07:50:51.717 4941-5795/com.qproject.main D/LeakCanary: |   Mthemeresource = 213123088412-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: |   Mbase = [email protected] (0x12d82600) 12-25 07:50:51.717 4941-5795/com.qproject.main D/LeakCanary: | Shadow$_klass_ = com.qproject.test.leakcanary.leakcanaryactivity12-25 07:50:51.717 4941-5795/com.qproject.main D/   Leakcanary: | Shadow$_monitor_ = 131636443012-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: * Excluded Refs:12-25 07:50:51.717 4941-5795/com.qproJect.main D/leakcanary: | Field:android.view.choreographer$framedisplayeventreceiver.mmessagequeue (always) 12-25 07:50:51.717 4941-5795/ Com.qproject.main D/leakcanary: | Thread:finalizerwatchdogdaemon (always) 12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Thread:main (always) 12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Thread:leakcanary-heap-dump (always) 12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Class:java.lang.ref.WeakReference (always) 12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Class:java.lang.ref.SoftReference (always) 12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Class:java.lang.ref.PhantomReference (always) 12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Class:java.lang.ref.Finalizer (always) 12-25 07:50:51.717 4941-5795/com.qproject.main d/leakcanary: | Class:java.lang.ref.FinalizerReference (always)
5. Get the Dump log file
If the tracking information is not enough to locate, Displayleakactivity also saved the last 7 dump files to the app directory for the developer by default, and can use tools such as mat to further analyze the dump file;
Vbox86p:/data/data/com.qproject.main/files/leakcanary # ls2016-12-25_07-50-51_718.hprof 2016-12-25_07-50-51_718. Hprof.resultd:\>adb pull./data/data/com.qproject.main/files/leakcanary/2016-12-25_07-50-51_ 718.hprof[100%]. Data/data/com.qproject.main/f...akcanary/2016-12-25_07-50-51_718.hprof
Android Studio->view->tool windows->captures, open the Captures window, cut the pull captured Hprof file into the directory of files in capture, double-click to open;

The specific analysis process, here is not focused on, we go to inquire mat related information;
v. Detection of other objects
If you want to listen to other objects (such as fragment), you can use the Refwatcher instance to achieve;

vi. principles of Leakcanary
The 1.refwatcher.watch () function creates a keyedweakreference weak reference object for the monitored object, is a subclass of the weakreference pair, adds a key-value pair of information, and then finds the weak reference object based on the specified key key;
2. In the background thread androidwatchexecutor, check if the keyedweakreference weak reference is already clear. If it still exists, after the garbage collection is triggered. After garbage collection, if the weak reference object still exists, a memory leak occurs;

Android tools: leakcanary-Memory Leak detection artifact

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.