如何控制 IE6+jQuery+jQuery-ui 内存泄漏?

Posted

技术标签:

【中文标题】如何控制 IE6+jQuery+jQuery-ui 内存泄漏?【英文标题】:How can I control IE6+jQuery+jQuery-ui memory leaks? 【发布时间】:2010-11-06 06:29:27 【问题描述】:

这是一个sample page 和几个日期选择器。这是 Drip 的结果:

alt text http://www.picvault.info/images/537090308_omoya.png

当我反复单击刷新按钮时,此页面在 IE6sp1 中无限期泄漏(IE6sp3+、Opera 9、Chrome2 和 FF3+ 似乎不错)。在我真正完全关闭浏览器之前,内存一直在上升并且永远不会下降。

我也尝试过使用最新的每晚 jquery (r6414) 和最新的稳定 UI (1.7.2),但没有任何区别。我尝试了各种没有成功的事情(CollectGarbage,AntiLeak,其他)。

我正在寻找“使用不同的浏览器!!1”以外的解决方案,因为我对此没有任何控制权。任何帮助将不胜感激!

更新 1: 我将该按钮事件添加到一个循环中,这就是发生的情况(突然下降是当我终止 IE 时):

更新 2:我提交了 bug report(手指交叉)。

更新 3: 这也在 mailing list 上。

更新 4:这(如邮件列表中所报告的)不起作用,实际上使事情变得更糟:

$(window).bind("unload", function() 
  $('.hasDatepicker').datepicker('destroy');
  $(window).unbind();
); 

仅仅调用destroy是不够的。我仍然被这个困住了,并且非常接近将 jquery 从项目中剥离出来。我喜欢它(我真的喜欢它!)但是如果它坏了,我就无法使用它。

更新 5: 开始赏金,另外 550 分奖励给一位乐于助人的人!

更新 6: 更多测试表明此漏洞存在于 IE6 和 IE6sp1 中,但已在 IE6sp2+ 中修复。现在,关于我到目前为止的答案......

到目前为止,所有答案都是以下任何一种:

    放弃 IE6sp0/sp1 用户或忽略 他们 调试 jquery 并自己解决问题 我无法重现该问题。

我知道乞丐不能选择,但那些根本不是我问题的答案。

我不能放弃我的用户。他们占用户群的 25%。这是一个为客户编写的自定义应用程序,旨在在 IE6 上运行。 放弃 IE6sp0/sp1 不是一种选择。 告诉我的客户只是处理它不是一种选择。它泄漏得如此之快,以至于五分钟后,一些较弱的机器无法使用。

此外,虽然我很想成为一名 JS 忍者,这样我就可以在 jquery 代码中寻找模糊的内存泄漏(当然这是 MS 的错,而不是 jquery 的错),但我也没有看到这种情况发生。

最后,多个人在此处和邮件列表中重现了该问题。如果你不能重现它,你可能有 IE6SP2+,或者你可能不够清爽。

显然,这个问题对我来说非常重要(因此有 6 次修订、赏金等),所以我对新想法持开放态度,但请记住,这三个建议都不适合我。

感谢大家的考虑和见解。请保持他们的到来!

更新 7: 赏金已结束,SO 自动接受了 Keith 的回答。很抱歉,只获得了一半的分数(因为我自己没有选择答案),但我仍然很困惑,所以我认为一半是公平的。

我希望 jquery/jquery-ui 团队可以解决这个问题,但我担心我将不得不将其写为“不可能(目前)”并停止使用部分或全部 jquery。感谢大家的帮助和考虑。如果有人对我的问题提出了真正的解决方案,请发帖,我会想办法奖励你。

【问题讨论】:

嘿,迈克,jquery 团队中没有人甚至懒得评论 google 组,这让我有点不高兴。我知道他们现在就在身边,因为他们评论了其他(更琐碎的)事情。我花了一些时间研究其他框架如何破坏元素。我开始越来越喜欢道场了!! 快速查看这个问题,它看起来像是IE6中的一个错误,而不是JQuery,微软在IE的更高版本中修复了这个错误。 JQuery 家伙可能厌倦了处理由网络浏览器的红头发继子 Internet Explorer 引起的问题。只是出于好奇,你为什么卡在 IE6 上? @nemo:是的,这绝对是一个 IE6 错误——但由于我无法让所有用户都升级到 IE6sp3+,所以 jquery 必须改变。很多很多企业用户都没有选择 IT 推出的内容,就我而言,我有数百台旧机器使用旧的、不受支持的 IE 版本访问该站点。 真的不能让客户升级到最新的IE6版本吗?我发现很多为 IE6 编写的应用程序不能在 IE7/8 上运行,但它们应该在 IE6SP2 上运行。 如果我可以使用一些服务器端代码来解决 IE 的错误,那就不会那么痛苦了。如果这样的修复是不可能的,我想我唯一的选择是(1)避免像 jquery/jqui 使用的 JS (2)升级 3 大洲的数百台机器。有趣。 【参考方案1】:

可用于 IE6 的最佳调试器是 Visual Studio。 (即使是免费版也可以。)正如 Janie 所提到的,如果您的问题只发生在 IE6 上,那么您需要在 IE6 上进行调试,特别注意只在其中运行的代码。

【讨论】:

我不知道为什么我们可以假设问题出在 jquery 中特定于 IE 的代码上……这是一个浏览器缺陷,jquery 需要解决,但目前不需要。跨度> 好点。这就是我的本意;我想还不清楚。【参考方案2】:

这个问题要么存在于 jQuery 的仅 IE6 部分,要么存在于缺少 IE6 特定代码的 jQuery 的一般部分(如 cmets 中所述)。无论哪种方式,它仍然是 jQuery 中需要解决的错误。 关于:空白 你要么必须dig yourself into jQuery 要么file a bug ticket。如果您设法修复它,请不要忘记将差异附加到错误跟踪器,以便项目变得更好。 ;)

如果我有空闲时间,我会尽力帮助你。

编辑

好的,所以这个问题似乎无法解决。

您面临的泄漏是 IE 6 SP 0 唯一的问题,这是由 IE 处理 DOM 的方法引起的泄漏。不管你用什么 JS 框架,它都不能正常工作。

因此,您当前的选择是:

Die trying 让您的用户将 IE 6 升级到更新的版本/Service Pack, 在 IE 中死掉(如泄漏)(失去客户)或 尝试在 IE 上工作而死。

但这并不一定意味着你不能解决这个问题。只是试图绕过这件事怎么样?

向每个非 IE 6 SP 0 用户显示 jQuery 日期选择器,只有 IE 6 SP 0 使用 IE 的 conditional comments 另一个更具弹性(可能是基本)的日期选择器。通过这种方式,您可以在软件中保留引人注目的功能/功能,并允许 IE 6 用户拥有相同的基本功能。

它可能不是一个干净的选项,但你仍然可以使用你想要的东西,而且 IE6 仍然可以在不泄漏的情况下工作。

唯一的问题是你将有一个更大的负担,因为你必须调试两个不同的日期选择器。但无论如何你都必须调试 IE 6,所以它可能是你目前最好的选择。

【讨论】:

我不知道为什么我们可以假设问题出在 jquery 中特定于 IE 的代码上……这是一个浏览器缺陷,jquery 需要解决,但目前不需要。跨度> 当然这是一个 IE 缺陷,但这就是人们首先使用 JQuery 的原因。我不想显得忘恩负义,但这仍然是 JQuery 中的一个错误。这可能是一个无法用 javascript 修复的 IE 错误,但对于 JQuery 和 JQuery 用户来说仍然是一个问题。就个人而言,我希望看到 IE6 染上一个痛苦、缓慢、混乱和血腥的死亡。 我想你误解了我的意思。你说这很可能是 jquery 的 IE-specific 代码的问题。我是说我们没有理由假设。相反,我敢打赌,实际上是 IE 的垃圾收集器阻塞了与大多数其他浏览器一起工作的代码 回应 Michael,它很可能不在任何现有的 IE 特定代码中,而是存在 should_be 一些当前不存在的特定于 IE6 的代码...【参考方案3】:

IE 6 的问题在于它有两个垃圾收集器。一个用于 JavaScript,一个用于 DOM。因此,例如,如果您将一个函数附加到一个 DOM 事件,然后删除该 DOM 元素,该函数仍将存在于内存中。

看看这个slide show。这有点讽刺,但它是很好的信息。

他们在 IE 7 中使用 fixed this issue。我在 Windows 7 的 IE8 中尝试了您的页面,但没有看到内存泄漏。

【讨论】:

非常有趣 - 是否适用于所有版本的 IE? 我不确定让我在谷歌上挖掘一下。我知道 IE 6 就是这种情况。 看起来他们在 IE 7 中修复了它。我会更新我的答案。 quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html 对不起,gradbot,这对我没有帮助。 当我这个周末有空闲时间时,我将不得不尝试一下。最近,我一直在解决 Project Euler 的问题。【参考方案4】:

在销毁 datepicker 对象后尝试删除这些对象:

$.datepicker = null;
$.fn.datepicker = null;

【讨论】:

@Michael Haren:您可以尝试将其添加到更新 4 中的 window.unload 处理程序中吗? 对不起,它仍然泄漏。它可能会稍微慢一些,但每次刷新仍然会泄漏 500-1000kb。不过,感谢您的建议。 这不会阻止泄漏,因为它是动态添加到 DOM 的 HTML 内容在页面刷新时没有被收集。【参考方案5】:

你能试试这个演示吗here。它使用与 dojo 实现相同的方法从 dom 中删除元素。一些快速测试似乎可以缓解泄漏,但不是完全但要好得多。

更新在花了一点时间之后,我确信这与日期选择器本身无关。

我的测试表明,只要每 1 秒重新加载一个虚拟页面,就会发现内存泄漏。 如果然后在此页面上包含 jquery,则泄漏会略有增加(解析脚本的开销)如果您随后将 jquery-ui 添加到混合中,那么内存泄漏会再次略有增加。

为了证明这一点,如果您避免重新加载页面,而是使用一个仅添加输入的按钮,在其上创建日期选择器然后将其删除,那么您几乎看不到任何泄漏。

【讨论】:

在不绑定日期选择器的情况下运行我的测试页不会泄漏。内存使用量略有上升,但趋于平稳。一旦我添加了 .datepicker() 行,它就会像疯了一样泄漏。【参考方案6】:

我不想这么说,你的方法是正确和专业的,但我很想离开它。

不解决此问题的后果是 IE6 用户会注意到他们的机器越来越慢,最终要么完全崩溃,要么更有可能导致 IE6 崩溃。

那又怎样?

真的 - 为什么这是你的问题?

您的网站肯定不会是他们访问此漏洞的唯一网站,无论您做什么,他们都会经常看到 IE6 崩溃,因为它就是这样做的。

仍然使用 IE6 的任何人都不太可能指出您的应用程序存在泄漏。

最后,当 IE6 崩溃时,它会将 IE6 报告为罪魁祸首 - 您可以合理地指出,这是微软在新版本中修复的 IE6 中的错误。

您的昂贵时间最好花在为那些没有被困在传统地狱中的用户改进应用程序上——您的应用程序基本上应该适用于 IE6 用户,但这类问题会占用您所有的时间,并且无法解决他们的问题。 IE6 仍然是一个不受支持的、崩溃的、浏览器的安全漏洞。

我怀疑 jQuery 开发人员的看法与我相似。此外,你必须做一些非常丑陋的事情来解决 IE6 中的这个错误,包括阻止泄漏但实际上要慢得多的 hacky DOM 工作。


更新

好的,这不是一个容易修复的问题 - MS 在此处描述 IE6 错误(并提供有关如何修复它的建议):http://msdn.microsoft.com/en-us/library/bb250448(VS.85).aspx

基本上这不是 javascript 或 jQuery 的问题 - 实际问题在于 IE6 DOM - 当 HTML 元素添加到页面时(通过 javascript,而不是在页面加载时)IE 不能垃圾收集它们,除非它们是以非常特定的方式创建的。

这是 jQuery UI 构建元素的方式(请参阅上面链接中的 DOM 插入顺序错误),因此这不是 jQuery 开发人员或您可以轻松修复的问题。

那么你如何解决这个问题?好吧,您可以坚持使用 IE6 的旧版弹出式日历,也可以编写自己的日历。

我会推荐前者,但如果你真的想构建后者,则需要遵循一些基本规则:

    始终自上而下添加元素 - 例如,如果您想构建一个表格,请将 <table> 元素添加到页面的 DOM 中,然后添加 <tr> 然后添加 <td> 等等。这是从前到后的,因为构建整个表然后将其添加到 DOM 中要快得多 - 不幸的是,这就是 IE6 忘记它的地方。

    只使用 CSS 和 HTML 3.2 属性 - 听起来很愚蠢,但 IE6 会创建额外的对象来存储额外的属性(或“expando”属性),这些也会泄漏。

    与 (2) 有点相关,但正如 @gradbot 提到的,IE6 存在垃圾收集 javascript 变量的问题 - 如果它们在从该元素触发的事件中引用 DOM 元素,您可能会遇到问题。 javascript 对具有“expando”属性的 DOM 元素的引用也加剧了这种情况。

如果您在网上浏览一下,可能已经有一个遵循这些规则的下拉 DHTML 日历 - 它不会像 jQuery UI 那样漂亮、快速或可配置,但我确定我'已经看到它在 IE6 中没有泄漏。

我认为最好的办法是尽可能保持静态 - 例如,您可以在页面中加载日历网格(周数和日期列标题),然后动态加载数字(仅此而已)。创建日期数字作为链接,在 href 中使用 javascript - 通常不是最佳实践,但在 IE6 中泄漏的可能性要小得多。

【讨论】:

顺便说一句,解决方法涉及以完全不同的方式将表构建到 DOM 中 - 这将涉及完全重写 jQuery UI 日期选择器控件,并且新控件需要几秒钟(IE6似乎挂起)进行渲染。 导致此泄漏的具体问题在这里:msdn.microsoft.com/en-us/library/bb250448(VS.85).aspx 问题是 DOM 插入顺序泄漏 @Keith:不幸的是,这是针对我公司编写的自定义应用程序。我有 25% 的用户运行 我的意思是,你可以让这 25% 的用户发生泄漏 - 他们的浏览器无论如何都会崩溃。您的应用程序基本上仍然可以为他们工作,我并不是说您根本不支持他们。由于 DatePicker 如何构建它显示的表,您无法使用 jQuery UI 修复此泄漏。您可以使用特定的仅限 IE6 的代码从头开始创建自己的代码,但这对他们来说仍然很慢。我自己的产品的客户群是 20-25% 的 IE6,我想在这里我会为这些用户删除 DatePicker 并要求他们输入日期。优雅地降级。 我认为最好的办法是让 IE6 用户使用旧日历。这样他们就不会失去任何东西,而您仍然可以为可以利用它的 75% 的用户增加价值。我发现,虽然 jQuery 在 IE 上的表现非常好,但 jQuery UI 中的任何东西往往都太过分了。在页面上做任何动态操作时,即使是 IE8 的性能也差得惊人。我发现自己回到了旧的设计口号,即定期优雅地降级。【参考方案7】:

很明显,您所描述的问题源于 IE6 中的一个缺陷,您无法通过软件修复(无论是 jQuery 更新、手动调用 CollectGarbage 还是其他一些 JavaScript/DOM hack)来破坏该缺陷.

在我看来,有 3 个选项可以解决这个问题。

    我想您的客户/用户使用 IE6 SP0 是因为某些公司标准或法规,或者甚至是因为他们仍在使用的某些较旧的 Web 应用程序不支持较新的浏览器。如果不能选择升级到 IE7(或因此升级到 IE8),您可以联系您客户的 IT 部门,并礼貌地指出用最新的服务包更新 IE6 不仅可以解决他们正在使用的应用程序的问题付费,但也修补了 IE6 SP0 中无疑存在的许多安全和性能缺陷。诚然,这可能不是一个舒服的情况,但它可能会解决您遇到的问题,同时仍然允许他们使用出于任何原因需要的浏览器。

    如果您可以让客户的 IT 部门相信 IE6 已经过时,他们可能愿意让您的用户升级到更新的浏览器。可以毫不夸张地说,运行 IT 部门的人会更愿意强迫员工升级软件,如果他们知道它要么 a) 充满缺陷和安全漏洞,要么 b) 接近其支持结束日期(如IE6 SP0 是)。 XP Pro SP2 上的 IE6 SP0 支持到 2010 年 7 月 13 日 - 所以它还有一些时间,但指出这一点以及您可能发现的其他缺陷/限制可能会让他们认真考虑尽快升级。

    如果您无法说服任何人将他们的浏览器升级到 IE6 SPX 或 IE7/8,那么我不知道您是否有选择,只能从您的页面中删除有问题的控件,并且追求不同的选择,直到用户的浏览器允许。网上肯定有许多日期选择器控件的实现可以满足您的需求。它可能不像 jQuery 版本那么时髦,但此时您没有太多其他选择。

希望你能找到解决办法!

【讨论】:

我认为 1 和 2 是进行切换的合理论据,但不幸的是我怀疑它们是否会起作用。公司经常有他们的人力资源、物流、工资单、采购、CRM、潜在客户管理、内部网和其他公司专门编写的所有其他内容。其中大多数也停留在 IE6 上,因为大公司从其他有同样问题的大公司那里购买基础设施。自 2 月以来,任何操作系统的任何版本都不再支持 IE6(尽管可以运行它的操作系统仍然是 XP),即使这样也没有将其作为企业客户的要求推出。 我同意它们可能行不通,但它仍然是一个应该考虑的选项,因此您可以说“我已经追求并用尽了所有其他选项。”我认为您提到的软件属于“某些公司标准/法规或某些不支持新浏览器的旧网络应用程序”的类别。至于 IE6 支持...根据微软的说法,仍然有几个场景仍然支持它:support.microsoft.com/gp/lifesupsps/#Internet_Explorer【参考方案8】:

这里的问题比“只是”jquery 更深一些。 Jquery 和许多其他浏览器“泄漏”了 DOM 对象和对象侦听器之间的循环引用。假设您有一个附加了侦听器的输入字段,然后您从 dom 中删除了该元素,并且在您的代码中没有对侦听器的任何引用。现在任何现代浏览器(>=ie7、ff、chrome、safari、opera)都会接受它并垃圾收集它,而 IE6 会认为因为有一个监听器附加到一个 dom 元素,它不应该垃圾收集 dom 听众本身。

为了解决这个问题,有些人使用了非常复杂的设计模式,例如在 Google Doctype 中的 events code 中突出显示。要解决 IE6 的问题,您确实需要重写 jquery 的一部分来解决 IE6 问题和/或切换到使用不同的库和/或不将应用程序中的任何事件侦听器附加到 DOM 事件。

【讨论】:

【参考方案9】:

看看这个清理 DOM 节点的 sn-p。您可能会发现它很有用。 https://***.com/a/9519996/139667

【讨论】:

以上是关于如何控制 IE6+jQuery+jQuery-ui 内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章

使用 jQuery-UI Sortable 控制占位符高度

jquery-ui 显示未捕获的类型错误

范围内的角度 jquery-ui 可选问题

jquery-ui,如何将光标恢复为默认值

jquery-ui 和 webpack,如何将其管理到模块中?

如何将 jquery-ui 与 nodejs 一起使用?