prebid / Prebid.js

Setup and manage header bidding advertising partners without writing code or confusing line items. Prebid.js is open source and free.
https://docs.prebid.org
Apache License 2.0
1.33k stars 2.09k forks source link

Browser memory use growing per ad refresh #352

Closed RobertLippens closed 8 years ago

RobertLippens commented 8 years ago

This is an issue we have struggled with (unsuccessfully) for some time with prebid. I have not seen an issue posted before here about this but we've had it since we've started using prebid and the current way we have to resolve it is doing a full-page refresh after some time.

We have ad auctions running between a handful of providers (openX, indexExchange, etc.) A before/after snapshot of the browsers memory use for our page in which we call refresh 10 times on a few ads yields the following: screen shot 2016-05-12 at 12 27 22 pm screen shot 2016-05-12 at 12 38 59 pm

As you can see - the heap allocation grows very substantially. As the experience of our page lasts much longer than this short period of time, the page quickly becomes unusable without a full page refresh to kill whatever is causing this memory leak. The slowdown this causes is especially apparent on mobile devices.

We've isolated the issue coming from the ad refreshes, turning off the prebid calls gets rid of the leak.

I saw in https://github.com/prebid/Prebid.js/issues/188 that the same scripts were being loaded again and again per ad provider. This is my best guess as to the source of the leak. I have tried cleaning both the window object and scrubbing the DOM manually via javascript on the page, but this does not seem to help.

Is it known that a refresh will cause this sort of browser behavior? Is there a good way to mitigate this (aside from lowering the refresh rate)?

mkendall07 commented 8 years ago

@RobertLippens thanks for the analysis. Mind posting your full bidder list? I would also suspect those as the primarily reason for growing memory. We can take a look at those libraries to try and isolate leaks.

RobertLippens commented 8 years ago

Sure thing: We are using aol, appNexus, indexExchange, openx, sonobi, sovern, and yieldbot. I have noticed in the head of the page that several of these providers call URLs with slightly different querystring params (usually a timestamp). For example, I believe this is from appNexus: http://ib.adnxs.com/jpt?callback=pbjs.handleAnCB&callback_uid=403bab67e75e28b5... http://ib.adnxs.com/jpt?callback=pbjs.handleAnCB&callback_uid=476ba982dd169651...

Of course, the page head gets filled with about 40 different script calls very quickly, and only grows over time.

I had tried to use Object.observe on the window object to watch as properties were added by these scripts to further isolate things, but sadly, browser security prevents watching the window object for changes.

Thanks for the quick response!

RobertLippens commented 8 years ago

@mkendall07 Doing a bit more digging in the issue history, I found this gem: https://github.com/prebid/Prebid.js/issues/159

This seems related to the issue at hand. Our prebid library is older than when this commit went in. Were there any perf differences noticed from this PR? https://github.com/prebid/Prebid.js/pull/242/files#diff-86d571de6e2be77b9e9aa02a2b847c41R11

mkendall07 commented 8 years ago

@RobertLippens Not all the libraries implement the caching. I starting digging into this a little bit and seeing we can optimize by implementing the caching for several of the bidders. More info to come

mkendall07 commented 8 years ago

@RobertLippens Do you happen to have any more info on this issue? I was able to do a limited amount of testing but don't have a conclusion yet on which bidders are the worst offenders.

RobertLippens commented 8 years ago

@mkendall07 Nothing new, I've taken sporadic attempts to try and resolve the issue through other means with no luck. My latest attempt involved checking the window object every refresh, finding what new keys were added and deleting them right before next refresh in an attempt to free up memory that they may have held onto. That and manually scrubbing the DOM did not work. I do notice that some providers will periodically (every few seconds) send a small amount of data over the wire, probably to send some information back to the provider. This may also result in unfreed memory due to references the setInterval (I assume thats what the ad is using) is referencing. Does prebid itself hold onto any ad specific information that gets aggregated over time? Somewhere, something is holding onto references that just keep piling on - garbage collection never catches this (triggering it manually in Chrome's timeline dev tab does not do anything). Wish I had more information to give - let me know if you have other specific questions.

RobertLippens commented 8 years ago

@mkendall07 Some insight - this issue does not appear to be related to prebid. Browsers which enable flash by default show this massive memory leak, browsers which do not (like Safari) do not. The problem appears to lie within the ads themselves. I'm going to continue looking for solutions to this, but Prebid does not look guilty here.

mkendall07 commented 8 years ago

@RobertLippens That's a really good finding, thanks for replying. Please do keep us updated on this, as we'd like to know if there is ways of preventing it. If it is only caused by flash, there might not be much we can do, except disabling flash plugin.

RobertLippens commented 8 years ago

I believe our course of action is going to be exactly that - talking to all the providers and having them disable Flash ads as much as they are able to detect it. No real actionable items for prebid itself.

mkendall07 commented 8 years ago

Ok. Closing this out. If you find any new info feel free to submit a new ticket.

rwlaschin commented 6 years ago

So there is another way to address this issue. We run ads on multiple applications and need to be very cautious of crashing or causing problems with our partners games.

If it's just memory leaks we contain the ads in a cross-domain iframe and destroy it after the playback is completed. This works for most of the problems. This issues this doesn't fix is when there are listeners that aren't cleaned. We noticed that even with destroying the iframe any listeners that weren't cleaned would eventually cause the messaging between the parent and the ad frame to stop working.

We have recently revamped our tech and are seeing if we can use a friendly iframe instead and still be able to clean up properly.