【问题标题】:"JScript - script block" and memory leaks - How to freeing up resources properly?“JScript - 脚本块”和内存泄漏 - 如何正确释放资源?
【发布时间】:2012-02-20 16:53:51
【问题描述】:

我在我的项目的部分视图中放置了一些 jquery 选项卡。我注意到 Visual Studio 的“解决方案资源管理器”在调试期间每次单击新选项卡时都会生成一个新的动态JScript - script block

即使我将$('#mytabs .ui-tabs-hide').children().remove();$(".ui-tabs-hide").empty(); 放在标签的show 事件中,也会发生这种情况。 脚本块包含我在选项卡调用的部分视图中放置的 javascript,因此每次我单击以前单击的选项卡时,都会出现一个新的 JScript 块:很明显,这会导致稳定性或内存泄漏问题...例如,我已经注意到某些计时器和绑定在我加载两次选项卡后无法正常工作。

我不知道问题是否是由调用包含脚本的部分视图的方式引起的。请注意我如何设置控制器操作(示例中的索引)。

这是我的环境:jquery 1.6.4 - jquery-ui 1.8.16 - IE 8.0.7601 我无法使用其他浏览器成功调试,因为 Visual Studio 似乎没有附加它们的进程并且不显示动态数据...

控制器

这是标签调用的动作示例

  public ActionResult Index()
    {
         if (Request.IsAjaxRequest())
            return PartialView("_Index");

        return View(); 
    }

以下是我的部分观点和脚本:

_Layout.cshtml

 ....
 <div id="body">  
    @Html.Partial("_TabsMenu");
 </div>
 ....

_TabsMenu.cshtml(包含标签菜单的部分视图)

 <div id="menutabs" class="content-wrapper">
    <ul >
        <li>@Html.ActionLink("Home", "Index", "Home")</li>
        <li>@Html.ActionLink("Test", "Index", "Test")</li>
         ...
    </ul>
 </div>

 <script type="text/javascript">
 $(function () {
     $('#menutabs').tabs({
         cache: false,
         show: function (event, ui) {
             $('#menutabs .ui-tabs-hide').children().remove(); // the content is removed , but the script is still in memory
             $(".ui-tabs-hide").empty(); // the content is removed, but the script is still in memory
         },
         select: function (event, ui) {
             $(window).unbind(); 
         }
     });
 });

(我什至尝试将脚本放在 div id 中,pheraps 很傻,但我想看看 DOM 中的脚本是否被删除了......但什么都没有)

Index.cshtml

  @{Html.RenderPartial("_Index");}

_Index.cshtml(包含问题的重复 jscript 对象的部分视图)

   <table id="list4"></table>
   <jQuery("#list4").jqGrid({
datatype: "local",
height: 250,
colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'],
colModel:[
    {name:'id',index:'id', width:60, sorttype:"int"},
    {name:'invdate',index:'invdate', width:90, sorttype:"date"},
    {name:'name',index:'name', width:100},
    {name:'amount',index:'amount', width:80, align:"right",sorttype:"float"},
    {name:'tax',index:'tax', width:80, align:"right",sorttype:"float"},     
    {name:'total',index:'total', width:80,align:"right",sorttype:"float"},      
    {name:'note',index:'note', width:150, sortable:false}       
],
multiselect: true,
caption: "Manipulating Array Data"});
            var mydata = [
    {id:"1",invdate:"2007-10-01",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"2",invdate:"2007-10-02",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"3",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},
    {id:"4",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"5",invdate:"2007-10-05",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"6",invdate:"2007-09-06",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},
    {id:"7",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"8",invdate:"2007-10-03",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"9",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"}
    ];
       for(var i=0;i<=mydata.length;i++)
    jQuery("#list4").jqGrid('addRowData',i+1,mydata[i]);

更新

JScript - 脚本块 1..N // 这是我在每个 JScript - 脚本块中看到的,在调试期间...我是 testint jqgrid。这是demo from Trirand's site

     <jQuery("#list4").jqGrid({
datatype: "local",
height: 250,
colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'],
colModel:[
    {name:'id',index:'id', width:60, sorttype:"int"},
    {name:'invdate',index:'invdate', width:90, sorttype:"date"},
    {name:'name',index:'name', width:100},
    {name:'amount',index:'amount', width:80, align:"right",sorttype:"float"},
    {name:'tax',index:'tax', width:80, align:"right",sorttype:"float"},     
    {name:'total',index:'total', width:80,align:"right",sorttype:"float"},      
    {name:'note',index:'note', width:150, sortable:false}       
],
multiselect: true,
caption: "Manipulating Array Data"});
            var mydata = [
    {id:"1",invdate:"2007-10-01",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"2",invdate:"2007-10-02",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"3",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},
    {id:"4",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"5",invdate:"2007-10-05",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"6",invdate:"2007-09-06",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},
    {id:"7",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"8",invdate:"2007-10-03",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"9",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"}
    ];
       for(var i=0;i<=mydata.length;i++)
    jQuery("#list4").jqGrid('addRowData',i+1,mydata[i]);                

【问题讨论】:

  • 您可以在大多数现代浏览器控制台中分析 javascript,这将是比在 IDE 中更好的测试。如果您的 jQgrid 测试直接来自演示,没有修改...我怀疑 VS 给您提供了错误的信息。如果是修改过的代码,你可能设置了某种过度递归

标签: jquery asp.net-mvc jquery-ui memory-leaks jquery-ui-tabs


【解决方案1】:

浏览器解析的脚本不在 DOM 中,您无法“删除”它 - 变量仍然定义,事件仍然绑定,方法仍然存在。如果您将 javascript 放入重复加载的局部视图中,您将重复获取该 javascript。

您需要做的是编写您的 javascript 以更好地适应这一点。如果您将事件绑定到动态区域之外的元素 - 不要。您将多次绑定它们。将该代码移动到只会加载一次的地方。尝试将动态区域中的 javascript 保持隔离,以便它只处理也在动态区域中的元素。

您还可以通过简单的 if 检查、使用范围更大的 jquery 选择器等来防止多个定义。

如果不详细说明该重复块中的内容,我将无能为力。

【讨论】:

  • 谢谢@bhamlin!我将涉及的javascript代码放入问题中。请您帮我避免这种不良行为并隔离问题吗?每个选项卡更改都会在内存中加载一个新脚本。我会避免这种情况,我认为这也可以帮助其他人。非常感谢!
  • 我猜list1 应该是ticketgridpager1 应该是jqpager。也就是说,每次加载脚本块本质上都没有错。如果有奇怪的行为,可能与 jqGrid 的实现方式有关,这可能超出了本问题的范围。如果您只想每次加载更少的脚本,您可以将该代码块作为一个函数放在 Index.cshtml 中,然后让 _Index.cshtml 调用它,传入列表和分页器元素进行操作。
  • 你是对的。这是一个拒绝。我更正了名称,并用静态数据举了另一个例子,所以每个人都可以测试和重现它。我知道每次加载脚本都没有问题,但正如我所说的那样,问题是 永远不会卸载脚本。此外,所有代码都在这里,每个人都可以测试和重现行为。 jqGrid 的实现非常简单,所以不幸的是,我认为这不是问题的关键。
  • “我说的问题是脚本永远不会被卸载”。脚本无法卸载,没有这种东西。
  • 所以脚本无法卸载。这对我来说似乎太奇怪了。怎么可能没有人实现一种方法来从未使用的脚本中释放内存?不存在设置到期、GC 或其他方式的方法吗?你能给我举个例子来重复使用相同的脚本并避免它重新加载每个选项卡更改吗?非常感谢您的帮助
【解决方案2】:

在我看来,您的问题是每次加载选项卡时,其中的所有脚本也会加载,就我而言,您无能为力,请记住您可以使用生成这些脚本的服务器端代码,因此 ASP.NET 必须表现得好像它们都是不同的(因为它们实际上可以是不同的)。

但是,javascript 是垃圾收集的,所以我认为您看到的那些脚本在您不调试时实际上不会占用用户的内存,调试器将始终显示加载的所有内容,无论是否已被垃圾收集(尽管我实际上并没有测试它)。

如果您担心内存问题,请确保您没有声明永远不会被垃圾回收的全局函数和变量(特别是在重新加载的范围内),为此,只需在它们周围加上一个

(函数(){

还有一个

})();

这样它们就在一个匿名函数中,可以在执行后立即进行垃圾收集。

【讨论】:

  • THX 爱德华多。你对 GC 的假设让我平静下来,无法确定,请你给我一些关于如何测试的建议,好吗?
  • 我在javascript内存泄漏link上找到了这个链接,它使用windows资源管理器来监视内存。
  • 不幸的是,我认为最好的办法是在您的选项卡中放置一些带有大字符串的 javascript,自动切换选项卡/单击直到满意,检查资源管理器。
  • 刚刚想起另一个在这种情况下可能有用的技巧,调试器;语句在任何浏览器中都充当断点,因此您可以在代码中放置一个断点,然后使用 firebug 或 chrome 开发工具在另一个浏览器中进行调试。
【解决方案3】:

您只需要在文档就绪事件中收集选项卡中的所有脚本。下面的代码找到一个元素的所有脚本子元素,执行它们然后销毁它们,因此它们不能再次执行:

function GlobalEvalScriptAndDestroy(element) {
var allScriptText = CollectScriptAndDestroy(element);
jQuery.globalEval(allScriptText);}



function CollectScriptAndDestroy(element) {
var allScriptText = "";
if (element.tagName == "SCRIPT") {
    allScriptText = element.text;
    $(element).remove();
}
else {
    var scripts = $(element).find("script");
    for (var i = 0; i < scripts.length; i++) {
        allScriptText += scripts[i].text;
    }
    scripts.remove();
}
return allScriptText;}

【讨论】:

  • THX 弗朗西斯科。我已经在文档就绪事件中收集了脚本。我也阅读了 Eduardo 的以下答案,他说脚本可能是 GC ......也感谢脚本。我已经在每个标签显示上做了$('#menutabs .ui-tabs-hide').children().remove();$(".ui-tabs-hide").empty();,它至少适用于html。你不觉得应该够了吗? Grazie ancora!
  • 对不起 Francesco,我想试试你的解决方案。你能告诉我我必须把代码放在哪里以及如何调用它吗?我想我必须调用标签的显示事件。 THX
  • 没有没有。在应用插件之前在应用选项卡插件的原始 div 上执行此操作...即在文档就绪事件中。这样,在创建选项卡时,脚本已经被删除......这样你就可以确定它们的存在不会干扰插件
猜你喜欢
  • 1970-01-01
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多