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):
Once I remove the AdView-related code (and again, this is the ONLY code of this application) the problem goes away:
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 ????
Basically, this isn't really an issue. What's happening is your activity is receiving onDestroy, doing its cleanup, and then waiting around for a GC run. When the GC happens, it sees this old context lying around and cleans up all the underlying gunk, but it doesn't appear to clear the Activity in that pass--this is why your "leaked" Activity has such a small footprint: it's basically a shell. On the next GC pass, it will be cleaned up.
You can see this yourself by firing up your activity, backing out (to trigger onDestroy), going back into the process, firing a GC and an hprof dump, waiting a bit, then firing another GC and hprof dump. In the first dump--in my testing at least--I saw results similar to yours: an extra activity lying around with a very small memory footprint. In the second dump, I saw only the currently running activity.
Donot merge your UI with Admob, You can run another thread to get ad from Admob. Also you can refresh the ad at particular interval of time. That will be easier for you to debug where the memory issue may be.
Thanks Deepak
I am using "play-services-ads:7.5.0" and it was not necesary to create de AdMobActivity. It worked by:
Creating adView dinamically
Removing all views from linearLayout on destroy and destroying adView
Unfortunatelly Interstitial still leaks
One way to fix this problem is to create one single instance of adview using your base activity of your application. Add this adview to any activity you want, but remember to remove it in the activities on destroy method.
This way the adview only leaks the base activity, which you almost never should have more than one instance of.
Example:
Here is my work around for this mess:
I've limited the memory leak, by using the same empty activity instance:
Further Ad would be created using the AdMobActivity.AdMobMemoryLeakWorkAroundActivity.
You also need to add the activity to the manifest of course:
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().
Another answer that addresses this issue, even though it is a pain to do so, is to follow the following steps.
unpersist all data that's needed from sharedPreferences or any other types of on storage persistence,
store those values in local variables/objects
WIPE ALL OF YOUR APP DATA
re-persist everything
You could start a service as your app is closing to do this. This would prevent data from getting really big due to the memory leak. Nasty way to address it, but I have tried it and it works.