Published

Fri 10 April 2015

←Home

Analyzing memory leaks in Android

In this post I will share an example of analyzing memory leak in an Android application. I recently tried to integrate a popular android library ShowcaseView which can be used for first run demos in your android application. The thing is while testing the library, I noticed severe memory leaks. This was occurring because references to ShowcaseView class were being kept. And, as bitmaps are created internally by this class to overlay the content, so each instance was holding a large chunk of memory.

Analyzing the issue

For heap analysis, I used VisualVM. First, thing you need to realize is that the heap dump taken from android cannot be directly analyzed with VisualVM or other tools such as eclipse MAT. You need to convert it to a format that these tools can analyze. For this you have to run the following command.

1
hprof-conv Snapshot_2015.04.10_19.37.29.hprof heapissue

Here the first parameter is the android heap dump and the second is the output file.


After loading the file into VisualVM for analysis, I could see the references of ShowCaseView class were being retained as it had GC roots, thus live references, which meant that the instances could not be collected by the JVM Garbage collector.


heap_issue_1


Simple OQL analysis revealed live paths to the instances.


Query:


1
select  heap.livepaths(u,false) from com.github.amlcurran.showcaseview.ShowcaseView u

heap_issue_2


As you can see phone decor view was holding references to the view which was added by ShowCaseView.  Thus, the decorview was holding reference to ShowCaseView instances.


Now, Ideally whenever the view has been displayed it should be destroyed, especially,  if it is holding such large chunks of memory. but, instead due to oversight from the developer instead of removing the view from decorview, he was just setting the views property to View.Gone, which only makes the view invisible and does not remove the view from the ViewGroup.


The Solution


The problem was then clearly with the fact that the added views should be removed after the ShowcaseView was hidden.  So, I just modified the hide() and hideImmediate() methods to remove the views that were added on top of the decorView.


I have mentioned one of those method below.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Override
    public void hide() {
        clearBitmap();
        // If the type is set to one-shot, store that it has shot
        shotStateStore.storeShot();
        mEventListener.onShowcaseViewHide(this);
        fadeOutShowcase();
        getViewTreeObserver().removeOnPreDrawListener(draw);
        if(Build.VERSION.SDK_INT>15){
            getViewTreeObserver().removeOnGlobalLayoutListener(globalLayout);
        }
        else {
            getViewTreeObserver().removeGlobalOnLayoutListener(globalLayout);
        }
//        removeView(ShowcaseView.this);
        ((ViewGroup)mActivity.getWindow().getDecorView()).removeView(ShowcaseView.this);
    }


Post, implementing these changes the library works as it is supposed to work, that is just fine.


heap_issue_fine_1


heap_issue_fine_2


showcaseview


Below, I have mentioned the Gist that contains the entire source code for the modified ShowcaseView. So, happy coding :-)


Go Top
comments powered by Disqus