Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AdView causes memory leak

I'm using AdView and LeakCanary. Fragment that hosts adView call adView.destroy() in onDestroy, but LeakCanary shows that Activity that hosts this fragment is leaked by com.google.android.gms.common.api.a.a.a.i . Heap dump also shows that there are memory leak. When I remove AdView.loadAd() and not loading Ad in fragment - there is no leak. Any thoughts or suggestions ? Thanks.

like image 367
Alex Perevozchykov Avatar asked Nov 03 '15 21:11

Alex Perevozchykov


People also ask

What is the main cause of memory leaks?

A memory leak starts when a program requests a chunk of memory from the operating system for itself and its data. As a program operates, it sometimes needs more memory and makes an additional request.

Do memory leaks cause permanent damage?

Memory leaks don't result in physical or permanent damage. Since it's a software issue, it will slow down the applications or even your whole system. However, a program taking up a lot of RAM space doesn't always mean its memory is leaking somewhere. The program you're using may really need that much space.


3 Answers

Same problem, AdView have an internal variable (strong reference) holding onto the context, which is my Activity, causing a leak of the Activity instance.

My dependency is com.google.android.gms:play-services-ads:8.3.0

A workaround is to supply the Application Context when creating the AdView instance.

AdView adview = new AdView(getApplicationContext());
like image 108
dvd Avatar answered Oct 20 '22 19:10

dvd


I think passing App Context to AdView is not a solution really. Because issue is that AdView is not freeing up Context Object. So it will not free up App Context if you pass it.

So below can be a workaround to prevent leak truely.

@Override
protected void onDestroyView() {
    super.onDestroy();
    if (adview != null && adview.getParent() != null) // inflated by XML and remove here from parent
        ((ViewGroup) adview.getParent()).removeView(adview);
    adview.destroy(); 
    adview = null;
}

1. Destroy Adview in onDestroyView

  • Fragment lifecycle has method onDestroyView, that is called when view is destroyed, so you should exactly destroy AdView at this place.
  • In your case you are destroying AdView in onDestroy (After onDestroyView) so it is a leak. Because AdView is still there after Fragment View is destroyed.
  • An Activity has NO onDestroyView method, view is destroyed in onDestroy in Activity. So there we clear objects in onDestroy.

2. Remove AdView from View programmatically.

But if we are using adView in XML then this cant be done.

Because you want inflate AdView from XML so removing View in onDestroy will do the job for you.

3. Make AdView NULL in onDestroyView

Make AdView null in onDestroy. Thus AdView object will not be referred anymore. and it will be cleaned by Garbage collector.

I hope this information is useful for you. :)

like image 3
Khemraj Sharma Avatar answered Oct 20 '22 21:10

Khemraj Sharma


Can you try the following:

  • move your logic in onDestroyView()
  • first remove your adView from its container and then call destroy(), i.e.

    ViewParent parent = adView.getParent();
    if (parent != null && parent instanceof ViewGroup) {
      ((ViewGroup) parent).removeView(adView);
    }
    
    adView.destroy();
    adView = null;
    
like image 2
Dimitar Genov Avatar answered Oct 20 '22 19:10

Dimitar Genov