massive memory leak in ios UIWebView

2019-01-09 01:39发布

问题:

looking for mem leaks elsewhere in our system, I created a 20 MB web page with a meta refresh tag. the idea was to move a lot data through our datapath code to confirm mem stability.

<html>
<meta http-equiv="refresh" content="1">
<body>
<div style="border: 1px solid red">
    Content loading
</div><!-- 20mb worth of comments -->
</body>
</html>

what I found was the uiwebview displaying that meta refresh page leaks memory very, very fast. the app memory hits 300mb in about 2 minutes and gets shot on a low mem warning, even when our code is not in play.

I have stopped the refresh loading and tried to dealloc the webview.

I have tried loadurl:"about:blank", loadhtml:"", javascript document close.

I also tried writing a recursive removeFromSuperview and removeFromParentViewController, reading that the private scrollview in the webview is a memory problem, but that memory is never freed. I can't seem to find a reliable way to close, dealloc a webview when we are done with it.

We have lived with a slow rate of webview leaking for quite a while and really want to find a way of assuring a webview can be fully cleaned up when we are done with it. We recently converted the app to ARC which did not change the memory rate.

I am considering trying a recursive loop through all the objects in the webview and see if they can be freed. instruments shows 20 mb of cfdatas, alive, for each refresh of the 20MB page, but does not show them as leaks. if i only deliver the response header and done to the urlprotocol client we run stably so was ale to confirm the memleaks in the rest of the data path, but this is such a dramatic test case result am hoping to find a webview mem leak solution once and for all.

Does any one have any better ideas or has anyone tried recursing through the objects in a uiwebview?

回答1:

The way I got rid of my UIWebView's memory leakage is by setting its HTML to the empty string. One place to do this is when the view controller containing the web view disappears:

- (void) viewWillDisappear:(BOOL)animated {
    if (self.isMovingFromParentViewController) {
        [self.wv loadHTMLString: @"" baseURL: nil];
    }
}


回答2:

A shout to all developers: Implementing didReceiveMemoryWarning is an absolute must when using a UIWebView!

And it's specially important when the UIWebView can navigate anywhere or to a page you know that causes UIWebView to have huge leaks, such as m.youtube.com.

A great and usually seamless way to fix the leaks is just reloading the page. In that way you don't need to care about the page becoming empty, and usually the user will be able to continue its work from where he left off.

In your view controller, override didReceiveMemoryWarning like this:

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    [myWebView reload];
}


回答3:

With iOS 8 and onwards, you are really in luck. WKWebView does not leak and has a much smaller memory footprint than UIWebView. Having tested it with image laden web pages containing complex Javascript, it performed well.

Apple's WKWebView Class Reference

nshipster on WKWebView

It's not perfect though. Then again hopefully imperfections will be resolved in time. Check out Shingo Fukuyama's tips on GitHub:

WKWebViewTips



回答4:

  • Weakify "self" in the blocks.

This was one of the important reasons that lead to holding up of WebView memory even when popped out the navigation stack.