Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

My interstitial Ad is causing a memory leak?

I also tried using the ApplicationContext but it still leaks for some reason.

Found a similar post about the issue here AdActivity leak on AdMob (SDK 7.0) for Android but without an answer.

Also tried to set the adlistener and the ad to null in onDestroy() but without any luck and still leaks the activity.

My code called in onCreate()

private void refreshInterstitial(){
        mInterstitialAd = new InterstitialAd(this);
        mInterstitialAd.setAdUnitId("AD_ID");
        mInterstitialAd.loadAd(new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).addTestDevice("877BCC97E130A0DC62B2E5770D854496").build());

        mInterstitialAd.setAdListener(new AdListener() {
            @Override
            public void onAdLoaded() {
                mInterstitialAd.show();
            }
            @Override
            public void onAdClosed() {
            }
        });
}

Leakcanary Leak Trace

 ┬───
    │ GC Root: Global variable in native code
    │
    ├─ mx instance
    │    Leaking: UNKNOWN
    │    ↓ mx.a
    │         ~
    ├─ com.google.android.gms.ads.internal.webview.w instance
    │    Leaking: UNKNOWN
    │    mContext instance of com.google.android.gms.ads.internal.webview.ay, not wrapping activity
    │    View#mParent is null
    │    View#mAttachInfo is null (view detached)
    │    View.mWindowAttachCount = 1
    │    ↓ w.a
    │        ~
    ├─ com.google.android.gms.ads.internal.webview.aa instance
    │    Leaking: YES (View detached and has parent)
    │    mContext instance of com.google.android.gms.ads.internal.webview.ay, not wrapping activity
    │    View#mParent is set
    │    View#mAttachInfo is null (view detached)
    │    View.mWindowAttachCount = 1
    │    ↓ aa.mListenerInfo
    ├─ android.view.View$ListenerInfo instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ View$ListenerInfo.mOnClickListener
    ├─ com.google.android.gms.ads.nonagon.ad.webview.f instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ f.a
    ├─ com.google.android.gms.ads.nonagon.ad.webview.l instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ l.e
    ├─ com.google.android.gms.ads.nonagon.ad.event.bs instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ bs.a
    ├─ java.util.HashMap instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ HashMap.table
    ├─ java.util.HashMap$Node[] array
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ HashMap$Node[].[1]
    ├─ java.util.HashMap$Node instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ HashMap$Node.key
    ├─ com.google.android.gms.ads.nonagon.shim.k instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ k.a
    ├─ com.google.android.gms.ads.internal.client.ae instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ ae.a
    ├─ com.google.android.gms.internal.ads.zzuc instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ zzuc.zzcbw
    ├─ com.test.Activity$1 instance
    │    Leaking: YES (aa↑ is leaking)
    │    Anonymous subclass of com.google.android.gms.ads.AdListener
    │    ↓ EqualizerActivity$1.this$0
    ╰→ com.test.Activity instance
    ​     Leaking: YES (ObjectWatcher was watching this because Activity received Activity#onDestroy() callback and Activity#mDestroyed is true)
    ​     key = 40a1eb8e-c9e6-4062-b5f7-053e642e812f
    ​     watchDurationMillis = 5288
    ​     retainedDurationMillis = 258
like image 278
Vince VD Avatar asked Feb 23 '20 05:02

Vince VD


People also ask

How do I get rid of interstitial ads?

When you're finished using the Banner Ad or Interstitial Ad, make sure to call the Destroy() method before dropping the reference. For an Interstitial Ad, Interstitial object can be used only once, it should be destroyed after displaying the Ad.

What causes memory leaks in Android?

Memory leaks occur when an application allocates memory for an object, but then fails to release the memory when the object is no longer being used. Over time, leaked memory accumulates and results in poor app performance and even crashes.


1 Answers

According to InterstitialAd Docs:

A single InterstitialAd object can be used to request and display multiple interstitial ads over the course of an activity's lifespan, so you only need to construct it once.

After looking at your code again, I noticed you re-construct mInterstitialAd every time refreshInterstitial() method is called. But according to the docs above, you should only construct mInterstitialAd once during onCreate().

In your case, the main cause of the memory leak: you still have an active listener (which is bound to Activity lifespan), yet you reconstruct a new InterstitialAd instance with another listener.

So, the solution is to reuse InterstitialAd instance and its listener without re-assigning. I suggest to simplify your refreshInterstitial() method to this:

private void refreshInterstitial() {
    mInterstitialAd.loadAd(new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).addTestDevice("877BCC97E130A0DC62B2E5770D854496").build());
}

Then put mInterstitialAd assignment to onCreate(). This solution is similar to the one you can find here.

like image 73
Harry Timothy Avatar answered Nov 02 '22 22:11

Harry Timothy