Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android AdMob causes memory leak?

Tags:

I've integrated AdMob v4.1.0 into my application and it seems to have caused a huge memory leak (pretty sure that it already happened on 4.0.4).

In order to isolate the problem I created a new project with a blank linear layout and added the AdView to it (this is actually a copy&paste from the sample code provided by AdMob). See my main.xml, MainActivity.java and manifest content:

main.xml:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical"     android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:id="@+id/linearLayout"> <TextView       android:layout_width="fill_parent"      android:layout_height="wrap_content"      android:text="@string/hello"     /> </LinearLayout> 

MainActivity.java:

package AdsTry.main;  import com.google.ads.AdRequest; import com.google.ads.AdSize; import com.google.ads.AdView;  import android.app.Activity; import android.os.Bundle; import android.widget.LinearLayout;  public class MainActivity extends Activity {      private final int AD_VIEW_ID = 1000000;       /** Called when the activity is first created. */     @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.main);           // Lookup R.layout.main         LinearLayout layout = (LinearLayout)findViewById(R.id.linearLayout);          // Create the adView         // Please replace MY_BANNER_UNIT_ID with your AdMob Publisher ID         AdView adView = new AdView(this, AdSize.BANNER, "MY_BANNER_UNIT_ID");         adView.setId(AD_VIEW_ID);          // Add the adView to it         layout.addView(adView);          // Initiate a generic request to load it with an ad         AdRequest request = new AdRequest();          adView.loadAd(request);                }      @Override     protected void onPause() {         Log.i("AdsTry", "onPause");          getAdView().stopLoading();          super.onPause();     }      @Override     protected void onDestroy() {         Log.i("AdsTry", "onDestroy");          getAdView().destroy();          super.onDestroy();     }      private AdView getAdView()     {         return (AdView) findViewById(AD_VIEW_ID);     } } 

manifest:

<application android:icon="@drawable/icon" android:label="@string/app_name">     <activity android:name=".MainActivity"               android:label="@string/app_name">         <intent-filter>             <action android:name="android.intent.action.MAIN" />             <category android:name="android.intent.category.LAUNCHER" />         </intent-filter>     </activity>      <!-- AdMobActivity definition -->     <activity android:name="com.google.ads.AdActivity"         android:configChanges="orientation|keyboard|keyboardHidden" /> </application>  <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 

And that's all the code I have.

Now, when running this application, I can see that both onPause and onDestory are called and the Activity is terminated, BUT the problem is that it will never be available for the GC since it causes the InputMethodManager to hold a reference to the Activity (See image taken from HPROF output after the activity was destroyed): MainActivity Merge shortest path to GC Roots

Once I remove the AdView-related code (and again, this is the ONLY code of this application) the problem goes away: Same HPROF output without using AdView

EDIT: Also tried removing ALL the code from onCreate and updated the main.xml to contain the following (still get the same result):

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"     android:orientation="vertical"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:id="@+id/linearLayout">     <TextView       android:layout_width="fill_parent"      android:layout_height="wrap_content"      android:text="@string/hello"     />     <com.google.ads.AdView     android:id="@+id/Ad"     android:layout_width="match_parent"     android:layout_height="wrap_content"     ads:adUnitId="MY_ID"     ads:adSize="BANNER"     ads:loadAdOnCreate="true"/> </LinearLayout> 

Any ideas ????

like image 391
Muzikant Avatar asked May 27 '11 06:05

Muzikant


2 Answers

I am using "play-services-ads:7.5.0" and it was not necesary to create de AdMobActivity. It worked by:

Creating adView dinamically

mAdView = new AdView(getApplicationContext(), AdSize.BANNER, banner_ad_unit_id); mAdsContainer.addView(mAdView); 

Removing all views from linearLayout on destroy and destroying adView

mAdView.setAdListener(null); mAdsContainer.removeAllViews(); mAdView.destroy(); 

Unfortunatelly Interstitial still leaks

like image 151
Julian Avatar answered Sep 28 '22 19:09

Julian


Here is my work around for this mess:

I've limited the memory leak, by using the same empty activity instance:

public final class AdMobActivity         extends Activity {      public static AdMobActivity AdMobMemoryLeakWorkAroundActivity;      public AdMobActivity() {         super();         if (AdMobMemoryLeakWorkAroundActivity != null)             throw new IllegalStateException("This activity should be created only once during the entire application life");         AdMobMemoryLeakWorkAroundActivity = this;     }      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         finish();     }      public static final void startAdMobActivity(Activity activity) {         Intent i = new Intent();         i.setComponent(new ComponentName(activity.getApplicationContext(), AdMobActivity.class));         activity.startActivity(i);     } } 

Further Ad would be created using the AdMobActivity.AdMobMemoryLeakWorkAroundActivity.

You also need to add the activity to the manifest of course:

<activity     android:launchMode="singleInstance"     android:name="com.nu.art.software.android.modules.admob.AdMobActivity" /> 

This implementation goes against my beliefs regarding static references, which are not constants, but this implementation prevents the leak because only one activity instance is used to create all the ads, and so no more activity leaks, plus the fact that the activity is completely empty.

NOTE: You should call the startAdMobActivity method from the application main activity onCreate method.

Adam.

UPDATE

This solution works only if you create the ad dynamically, and add it to the layout with code... and don't forget to destroy it in the Activity.onDestroy().

like image 26
TacB0sS Avatar answered Sep 28 '22 18:09

TacB0sS