Chrome无法释放内存,垃圾收集不会按预期发生(Mootools / MochaUI库)

时间:2010-10-31 17:12:13

标签: google-chrome garbage-collection mootools javascript

背景:我目前正在使用一个使用MochaUI库的Intranet站点(使用virtual desktop demo)。我正在使用Mootools 1.2.4和MochaUI 0.9.7。在我的“虚拟桌面”实现中打开的窗口通过iframe加载其内容。在css和脚本方面,一些加载的页面非常大,因此当用户关闭窗口时,Window对象充分地被垃圾收集是很重要的。这显然是由图书馆照顾的(使用Firefox时它确实做得很好)。

更新 最近发布的问题因后续编辑/更新而变得过长。标题不再准确,所以我也改变了。另外,请参阅下面的答案以获得部分解决方案。

以下是要点:

  1. Chrome就像这样:

    • Chrome无法释放为MochaUI窗口对象关闭时分配的内存。相反,Chrome的内存使用量(在字面上)冻结在窗口加载其iframe内容后达到的水平,设置内存使用量的下限直到刷新页面。
    • 随后的窗口打开/关闭,该过程使用的内存继续增加。最终,达到某种类型的上限,内存使用量停止攀升,陡峭/开始振荡而不是急剧上升。
    • 当有问题的窗口加载相当大的(内存方面)iframe内容时,这个问题最为明显。我用于所有测试目的的窗口在其iframe中加载了一个580 kb的页面(未缓存)。
  2. 奇怪的是,

    时会发生预期的垃圾收集
    • 随后将浏览器最小化
    • 在同一浏览器窗口中打开另一个标签
    • 正在开发人员工具中记录内存时间轴。 (喜剧选项)
    • 这种行为是否表明了解决#1的可能方法?

2 个答案:

答案 0 :(得分:6)

我不确定这是否在Windows中进行了测试,但如果是这样,请记住,无论何时最小化Windows中的窗口,它都会将所有数据移动到页面文件中。当再次打开窗口时,除非程序试图访问它们,否则它不会移回内存块,因此任何垃圾都会停留在页面文件中但实际上并未收集。

如果你自动化它,它不仅会减慢程序速度,也不会对任何内存问题有所帮助。

请参阅以下网址了解更多信息

https://micksmix.wordpress.com/2010/01/08/why-does-task-manager-show-an-applications-memory-usage-drop-after-minimizing-it-to-the-the-taskbar/

答案 1 :(得分:3)

<强>更新
MochaUI closingJobs函数的以下更改比我之前在此处发布的改进。主要的变化是现在通过更改src属性手动调用iframe的onunload事件,而不是在windowEl.destroy方法从DOM中删除iframe时触发。 (从here获得了想法。

如果您想使用此代码,只需删除现有的closingJobs函数并复制粘贴此代码。 应该使用0.9.7和0.9.8 MochaUI,以及Mootools 1.2.4或1.3。


closingJobs: function(windowEl){        
    windowEl.setStyle('visibility', 'hidden');
    var instances = MUI.Windows.instances;
    var instance_id = windowEl.id   
    var cleanup_delay = 50;

  /*
  Reset canvases with width/height = 0.
  This pretty reliably frees a few hundred Kb of
  memory in chrome.
  */        
    instances[instance_id].canvasControlsEl.width = 0;
    instances[instance_id].canvasControlsEl.height = 0; 
    instances[instance_id].canvasEl.width = 0;
    instances[instance_id].canvasEl.height = 0;         

    if(instances[instance_id].options.loadMethod == 'iframe')
    {
 /*
 The following line determines how long to delay the execution of
 the windowEl.destroy function. The line below gives 10 milliseconds 
 per DOM element in the iframe's document.
 You could probably do just as well with a hard-coded value.
 */         
        cleanup_delay = instances[instance_id].iframeEl.contentDocument.getElementsByTagName("*").length * 10;              

 /*
 Set the Browser property in the iframe's window to Internet Explorer.
 This causes Mootools to run its purge function, which iterates over
 all the iframe document's DOM elements, removing events/attributes etc.
 Assuming you have mootools included in the iframe content.     
 */
        if(instances[instance_id].iframeEl.contentDocument.defaultView.MooTools)
        {           
            if(instances[instance_id].iframeEl.contentDocument.defaultView.MooTools.version.contains("1.3"))                
                instances[instance_id].iframeEl.contentDocument.defaultView.Browser.ie = true;
            else        
                instances[instance_id].iframeEl.contentDocument.defaultView.Browser.Engine.trident = true;
        }                   

        instances[instance_id].iframeEl.src = "javascript:false";
    }       

    MUI.cleanWindow.delay(cleanup_delay, null, windowEl);       
},  

cleanWindow: function(windowEl)
{                               
    var instances = MUI.Windows.instances;
    var instance_id = windowEl.id
    if (Browser.ie){
        windowEl.dispose();
    }
    else {
        windowEl.destroy();
    }       
    instances[instance_id].fireEvent('onCloseComplete');

 /*
 Changed - Only execute getWindowWithHighestZindex() and focusWindow() 
 functions if there will actually be open windows after the 
 current one closes.
 */
    if (instances[instance_id].options.type != 'notification' && instances.__count__ > 1){
        var newFocus = MUI.getWindowWithHighestZindex();
        MUI.focusWindow(newFocus);
    }       
    if (this.loadingWorkspace) this.windowUnload();
    if (MUI.Dock && $(MUI.options.dock) && instances[instance_id].options.type == 'window'){
        var currentButton = $(instances[instance_id].options.id + '_dockTab');
        if (currentButton != null){
            MUI.Dock.dockSortables.removeItems(currentButton).destroy();
            currentButton = null; //Is this necessary?
        }           
        MUI.Desktop.setDesktopSize();
    }

    //Changed - moved this to the end of the function.
    delete instances[instance_id];  
}