I have a test project which demonstrates a memory leak caused by Admob 4.1.1.
The basic scenario is I have two activities and I switch back and forth between the main and the sub activity several times. I then switch to DDMS and force a few GCs. Then dump the HPROF and look at the historgram filtered by com.test* to see how many instances of the main and sub activity there are. My screenshots of the histogram are attached:
A leak!
I then commented out the ads in the xml and reran and there were no leaks:
No leak now
I have found some relevant posts to Admob leaks such as here: Android AdMob causes memory leak?
Here is a list of things I have tried to resolve the issue:
- Wait some amount of time and then force gc
- Do not load the ad in oncreate but spawn a thread to wait then load it
- Tried a previous version of Admob (the one not written by Google)
- Called adView.destroy() in the onDestroy() activity's method
- The unbinding from this link
Obviously none of these things helped.
Here is the test project I wrote:
(Be sure to set your own publisher id when you run the test project)
download test leak android project
If it makes a difference I'm tesing on my SGS2 with Cyanogenmod ROM.
Does this happen for other people when they run this project?
Does anyone know the cause a fix or a workaround?
Thanks
My app uses 80% of the allowed 16Mb and the AdView leaks at every orientation change (since android destroys and recreates the whole activity then). As a result I am out of memory after a dozen or so orientation changes giving me the dreaded:
10-08 10:14:47.178: ERROR/dalvikvm-heap(2876): 1440000-byte external allocation too large for this process.
10-08 10:14:47.178: ERROR/dalvikvm(2876): Out of memory: Heap Size=5191KB, Allocated=2877KB, Bitmap Size=18675KB
10-08 10:14:47.178: ERROR/GraphicsJNI(2876): VM won't let us allocate 1440000 bytes
or similar.
The increase in memory can easily be seen in eclipse by doing a debug run and opening Window > Open perspective > Other > DDMS, clicking the "update heap" icon and doing a Cause GC. The easiest way to check imho is the #Objects. If the orientation has changed from portrait to landscape and back, the number of Objects should be exactly the same (and without AdView it is).
I work around the memory leak by making the AdView static
private static AdView mAdView = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(mAdView == null)
{
mAdView = new AdView(this, AdSize.BANNER, ADMOB_PUBLISHER_ID);
}
}
and not calling the destroy
@Override
public void onDestroy() {
super.onDestroy();
//mAdView.destroyDrawingCache();
//mAdView.destroy();
//mAdView = null;
}
At least this prevents memory leaks between every orientation change.
Also I set request to null after using it. Don't know if that helps.
AdRequest request = new AdRequest();
mAdView.loadAd(request);
request = null;
My solution
private void destroyWebView(ViewGroup viewGroup) {
for (int i = 0; i < viewGroup.getChildCount(); i++) {
if (viewGroup.getChildAt(i) instanceof WebView) {
WebView view = (WebView) viewGroup.getChildAt(i);
viewGroup.removeView(view);
view.destroy();
return;
}
}
}
@Override
protected void onDestroy() {
mAdView.stopLoading();
destroyWebView(mAdView);
((ViewGroup) mAdView.getParent()).removeView(mAdView);
Yes, I build it all up dynamically. I use removeAllViews to remove all views from my (LinearLayout) container. Then I use addView to put them all back again.
The ad is clickable. Is there perhaps some transparent view in front of it in your case?