UIWebView secrets - part1 - memory leaks on xmlhttprequest

My first blog post on iphone subject reveal a big memory bug when using UIWebView component. This is the (only one) component to display some HTML content in an iphone interface. UIWebView object has a lot of differents issues and I'm going to highlight the biggest of them. Actually, all XMLHttpRequests used in javascript code are fully leaking!!! I mean when you do a request that retrieve 100ko of data, your memory used grow up for 100ko! This bug is not always active, but almost always. In fact the trigger to enable it is to simply open one link in your UIWebView. For example, clicking on a <a> link.

But let's look at a memory usage graph while we execute this simple test application: memory usage graph

  1. Create the UIWebView object
  2. Load a local HTML test file
  3. Execute 3 XMLHttpRequest to google.com, notice how the memory is freed three times after each request!
  4. Trigger the leak by opening a page that redirect back to our test file
  5. Execute the same 3 XMLHttpRequest and look how much memory is used and totally leaked :/
  6. We clean the HTML document with document.body.innerHTML=''; (sometimes free some memory, when we have a lot of DOM objects)
  7. release the UIWebView (almost no memory freed, next post is going to analyse that)

Test Application


So, to sum up, usually, when you execute this Javascript in a UIWebView:
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
      // Do whatever you want with the result
      
}

}; xmlhttp.open("GET", "http://your.domain/your.request/...", true); xmlhttp.send();

Your are going to have a big memory usage and leak a lot of data!

But there is a hack to solve this problem: revert what is done when you open a link.
In fact, the key property which leads to this leak is the WebKitCacheModelPreferenceKey application setting. And when you open a link in a UIWebView, this property is automatically set to the value "1". So, the solution is to set it back to 0 everytime you open a link. You may easily do this by adding a UIWebViewDelegate to your UIWebView :

- (void)webViewDidFinishLoad:(UIWebView *)webView {
  [[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"WebKitCacheModelPreferenceKey"];
}
So are you going to have much less crash due to "Low Memory" :)

Comments

You can use your Fediverse (i.e. Mastodon, among many others) account to reply to this post
(Note that comments from locked accounts won't be visible on the blog, but only to me)