UIWebView和Javascript的内存泄漏问题

10

我正在尝试修复由我的UIWebView引起的一堆泄漏问题,但找不到它们的来源或解决方法。 我所做的是通过网络请求获取一些内容,然后组装我的HTML并动态加载它:

NSString* body = <some HTML>;
NSString* html = [NSString stringWithFormat:kHTMLTemplate, [self scripts], [self styles], body];
[_webView loadHTMLString:html
               baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
每次有新内容可用时,我都会再次执行loadHTMLString以刷新Web视图。 我重复使用相同的Web视图,相同的控制器,相同的一切。
Instruments显示了一个非常奇怪的模式,其中所有泄漏的对象都是各种大小的General-blocks,并且没有任何信息附加:没有负责的库,没有负责的框架等。每次执行loadHTMLString时,都会添加新的泄漏。
似乎在S.O.上有几个关于UIWebView泄漏内存的线程。 我尝试过我找到的所有建议(例如将NSURLCache设置为零或重置它;每当我有新数据时,我尝试释放现有的UIWebView并分配一个新的UIWebView等),但什么也没帮助。
到目前为止,我的调查得出了一个明确的结果:如果我加载到视图中的HTML包含某些Javascript,则泄漏只出现在此时。如果您注意上面的html字符串,它由几个组件组成; 其中之一是[self scripts],它是一个简单地返回以下内容的函数:
return @"<script type='text/javascript' src='jquery-1.4.4.min.js'></script>"
        "<script type='text/javascript' src='jmy.js'></script>";
如果我去掉它,就没有泄漏了。但是只要我在HTML中添加一个 <script> 标签,泄漏就会出现。即使我只是包括jQuery文件(或任何其他js文件,对于这一点也是如此)。
return @"<script type='text/javascript' src='jquery-1.4.4.min.js'></script>";

问题是:有人知道这里发生了什么吗?明显地,将一个Javascript文件包含到我的HTML中会导致UIWebView泄漏内存。

泄漏出现在我重用同一UIWebView对象或每次有内容时实例化一个新对象的情况下,这表明loadHTMLString处理javascript文件的方式可能导致泄漏。

有人知道如何解决这个问题吗?

enter image description here


这可能是UIWebView中的一个bug。http://blog.techno-barje.fr/post/2010/10/04/UIWebView-secrets-part1-memory-leaks-on-xmlhttprequest/ - user529758
@H2CO3:谢谢,我也试过了...没有改善... - sergio
我认为我们被iOS 8拯救了。请查看WKWebView上的这个答案:https://dev59.com/qGQn5IYBdhLWcg3w36M1 - Max MacLeod
1个回答

11

我终于找到了一些线索,知道发生了什么事情,并且最重要的是我想分享一个解决方法。

我可以确认,简单地包含一些JavaScript文件会导致在网页视图重新加载时发生内存泄漏。我甚至尝试通过构建一个带有HTML内容的文件,然后通过loadRequest将其加载到UIWebView中,并通过reload重新加载它;但内存泄漏问题始终存在。我将为此发布一个radar。

救我的方法是使用innerHTML来更新网页视图的内容。我不再依赖于reloadloadHTMLString,而是使用一个空的初始化我的网页视图(我的意思是,head部分存在,包括所有必需的JS/CSS文件),然后设置document.body.innerHTML来更新它:

body = [body stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"setBody(\"%@\");", body]];

假设 setBody 被定义为:

var setBody = function(body) {
    document.body.innerHTML = body;
}
我获得了两个好处:网页视图更新变得非常快(这是不更新DOM的效果,但另一方面在整体上并不完全理想),而且在仪器下运行应用程序时没有内存泄漏。缺点是我必须微调几个条件,以确保应用程序正常运行;具体来说:

  1. 加载网页视图(即使是一个空白页面)需要很长时间,因此您必须将其内容的第一次更新与DOM就绪同步;

  2. webViewDidFinishLoading 似乎不可靠:它在 document.readyState 变为 complete 之前执行;

  3. document.documentElement.height,检索页面高度的官方方法也不可靠:解决方法是获取 body 部分的“计算样式”并读取其 height 值。

希望这能帮助其他发现他们的网页视图存在内存泄漏问题的人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接