AdMob 4.1.0 memory leak ?

1,305 views
Skip to first unread message

Muzikant

unread,
May 27, 2011, 11:37:16 AM5/27/11
to Google AdMob Ads Developers
Hi,
I'm struggling with the new SDK for the last two days to resolve a
memory leak issue I have.
I've managed to isolate it to make sure that it only happens when I
use the AdMob SDK by creating a new application, copy&paste the sample
code from the latest release (with a few minor modifications as the
sample is not updated to the latest changes of the sdk...) and I'm
definitely getting a memory leak just by using the SDK.
I've posted the detailed code here
http://stackoverflow.com/questions/6148812/android-admob-causes-memory-leak
including images from MAT showing the cause for the leak.
Just to be clear - when I remove the AdView-related code, the leak
goes away.

Any help will be greatly appreciated. If this can't be resolved soon
I'm afraid the next step is removing the ads from my applications...

Thanks

Emanuel Moecklin

unread,
Jun 7, 2011, 12:32:01 PM6/7/11
to google-adm...@googlegroups.com
Hi Muzikant

I did a lot of research on the topic in the last few days because I get many crash reports due to OutOfMemoryErrors.
Here's what I found related to the AdMob 4.1.0 code (I found other issues in my own code as well):
  • If I remove the line AdView.loadAd(AdRequest); my problems go away
  • If I rotate my phone by 90 degrees there seems to be no memory leak (but that's not the complete truth, more to that later)
  • If I rotate my phone by 180 degrees one instance of my activity is leaked BUT if I wait long enough the "dead" activity instances are garbage collected
  • If I rotate my phone a couple of times memory usage increases till the app crashes
So here's what happens:
  • if you rotate the phone by 180 degrees two orientation changes are registered (landscape - portrait - reverse landscape e.g.)
  • On the first orientation change AdMob tries to load an ad in an AsyncTask but because the activity is being destroyed due to the second orientation change the ad can't be loaded (I guess the server terminates the connection because it already got a new request)
  • BUT the AdMob client doesn't cancel its request but times out after 60 seconds only
  • Because the WebView holds a handle on the Context the activity is only released after the 60 second timeout which is exactly the behavior I observed: after 60 seconds memory usage drops to its old value before the 180 degree rotation
So it's not really a memory leak because the memory is released eventually but it's sufficient to crash any phone after a couple of rotations (depending on the size of the leaked activity of course, that's why I could never reproduce the problem with my test activity but only with one of my real applications as the memory print of my test activity was just too small).

I did some more research using JAD to analyze the AdMob code. Quintessence is that everything looks ok except the class that loads the ad. It's an AsyncTask (class b <-- ProGuard obfuscated name).
Its cancel method is called from another AsyncTask (class c) but as most of us know by now the cancel method doesn't do much, if the doInBackground code doesn't check isCancelled regularly and ceases its execution.

I hope that my findings finally convince AdMob that their SDK does have a serious issue even if its not a memory leak and that they do something about it like cancelling the AsyncTask properly or even better not keep a handle on the context at all.
In the meanwhile I try to find a workaround to prevent the app from crashing due to the sloppy AsyncTask implementation

Best Regards
Emanuel Moecklin
1gravity LLC

William Ferguson

unread,
Jun 7, 2011, 6:30:31 PM6/7/11
to Google AdMob Ads Developers
Actually Emanuel, it's a bit worse than this.

Because the request handling is performed using the AsyncTask class it
means that those requests are queued depending upon which version of
Android is being used. In Android 1.5 and 3.0 there is a single queue,
in Android 1.6 to 2.3 there is a exhaustible thread pool of 5 that
handles ALL AsyncTask requests.

So if you have rotated enough times to consume all threads available
to AsyncTask (ie one in Android 1.5 and 3.0 and five on the others),
all your Admob requests will be queued up and won't even have started
let alone have a chance to finalize and release their memory (and the
memory of their long finished Activity).

Admob (and probably everyone else) should use an AsyncTask replacement
that is more configurable.
I talked about this at length
http://design-counts.blogspot.com/2011/05/asynctasks-where-you-control-processing.html

Unfortunately that may not be enough because I suspect Webview is
itself using AsyncTask.
But that's another story.


On Jun 8, 2:32 am, Emanuel Moecklin <1gravity...@gmail.com> wrote:
> Hi Muzikant
>
> I did a lot of research on the topic in the last few days because I get many
> crash reports due to OutOfMemoryErrors.
> Here's what I found related to the AdMob 4.1.0 code (I found other issues in
> my own code as well):
>
>    - If I remove the line AdView.loadAd(AdRequest); my problems go away
>    - If I rotate my phone by 90 degrees there seems to be no memory leak
>    (but that's not the complete truth, more to that later)
>    - If I rotate my phone by 180 degrees one instance of my activity is
>    leaked BUT if I wait long enough the "dead" activity instances are garbage
>    collected
>    - If I rotate my phone a couple of times memory usage increases till the
>    app crashes
>
> So here's what happens:
>
>    - if you rotate the phone by 180 degrees two orientation changes are
>    registered (landscape - portrait - reverse landscape e.g.)
>    - On the first orientation change AdMob tries to load an ad in an
>    AsyncTask but because the activity is being destroyed due to the second
>    orientation change the ad can't be loaded (I guess the server terminates the
>    connection because it already got a new request)
>    - BUT the AdMob client doesn't cancel its request but times out after 60
>    seconds only
>    - Because the WebView holds a handle on the Context the activity is only

Emanuel Moecklin

unread,
Jun 7, 2011, 8:51:02 PM6/7/11
to google-adm...@googlegroups.com
Hi William

Thanks for elaborating on AsyncTask.
I never liked AsyncTask because its added value compared to standard Java threads is relatively small but it comes with some nasty pitfalls.
In general I prefer POJT (plain old Java threads;-). In some cases I'm using my own thread pool implementation and never had any problems with it.

Cheers
Emanuel Moecklin
1gravity LLC

Jim

unread,
Jun 7, 2011, 10:21:30 PM6/7/11
to Google AdMob Ads Developers
Guys,

I had the same problem. To work around it, I delay the ad request, so
my users can rotate rapidly all they want. Apparently, that's what
they wanted to do, because I got a lot of these errors.

I build my AdView in onCreate (because you can't do it on another
thread), then put the ad.loadAd(adRequest) in a "GetAd" Runnable. The
"GetAd" is executed with runOnUiThread (because you can't do it from
another thread either), which I post from another "AdHandler" thread I
start in onCreate. So, the AdView constructs, "GetAd" starts, waits
for a bit, then posts "AdHandler" to run ad.loadAd(adRequest) (which
is then AyschTask executed, unfortunately).

I pause 1000 ms. I suppose I could make it shorter, but I was getting
the error because I have an activity where a lot of my users will
enter the activity and immediately (or nearly immediately) slide out
the keyboard/rotate the phone. If the activity dies before the
thread.wait() ends, so does the thread and the AsychTask queuing
problem is reduced.

Well, it works except now I get an occasional NPE from the "c.a" class
- which from your comments above seems to be the cancellation
AsychTask trying to kill my AdView that is no longer there due to
phone rotation. To complicate things, I noticed my app cache would get
very large (not only do my users like to rotate the phone, but they
sit in the app and cache ad images). So, I implemented a forced cache
delete. I haven't seen this specifically create a problem, but I
haven't been able to rule it out yet, either. I'm worried the cache
delete causes the "c.a" class to NPE from time to time, but I had
users with persistent 6MB+ cache; and the performance problems that go
with that kind of thing.

Are you guys seeing this problem? The pause on the ad request means
fewer errors, but every error is still a FC to the user... in my app.
The cache delete also helped put the brakes on the OutOfMemory errors.

Thanks,
Jim
SPA
Message has been deleted

Emanuel Moecklin

unread,
Jun 7, 2011, 10:31:34 PM6/7/11
to google-adm...@googlegroups.com
Hi Jim

That's exactly the solution I came up with too, I just put the following code into the onCreate:

new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if (!isBeingDestroyed) Helper.setupAdNetwork(SudokuPlayActivity.this);
return true;
}
}).sendEmptyMessageDelayed(0, 1000);

To prevent the NPEs I check for the activity being destroyed (isBeingDestroyed is set to True in the onDestroy method). Access to isBeingDestroyed should be synchronized (wanted to make the example short).
Of course it's a hack and it won't eliminate all crashes but it's better than nothing and only Admob can really solve the issue.

I'll check out the cache problem but actually I hope Admob will come up with a fix quickly...

Claus Krag

unread,
Aug 5, 2015, 2:57:33 AM8/5/15
to Google Mobile Ads SDK Developers
Has there been any news on this since? I am reporting the same issue with AdMob requests as Emanuel is reporting (leak if device is rotated) on my nexus 5, running Lollipop (5.1)

Elton Kent

unread,
Aug 5, 2015, 5:36:32 PM8/5/15
to Google Mobile Ads SDK Developers
Hi Claus,
Could you please provide me a bit more background on what you're facing? Also, provide the SDK version that you currently use.

Thanks,
Elton Kent
Mobile Ads SDK Team
Reply all
Reply to author
Forward
0 new messages