火狐浏览器内存占用高,如何使用JavaScript释放?

3
我注意到使用Firefox几个小时后,它会占用超过2GB的内存。这种情况尤其在使用Ajax上传器上传大文件(100MB-400MB)或打开多个图像时发生(例如,在网页上总共有16MB的图像)。

问题是即使上传完成或关闭图像页面后,内存仍然没有被释放,Firefox仍然保持着2GB的内存占用。 是否可以从JavaScript中以某种方式释放内存,例如在上传完成后或图像加载完成/关闭后?

编辑about:memory: 1,172.03 MB(100.0%)-- 明确

├──1,000.00 MB(85.32%)-- js

│ ├────863.97 MB(73.72%)-- compartment([System Principal], 0x5083000)

│ │ ├──819.31 MB(69.91%)── string-chars

如何清空string-chars?我非常确定这是在将文件读入内存并使用ajax上传时出现的。

编辑2

以下是导致该内存使用情况的递归函数:

function uploadAjax(file, startByte, index)
{
    if(startByte==0)
    {
        $('#progress'+index).html(' ').progressbar( "destroy" ).progressbar();
        $('#asyncuploadsingle'+index).attr('disabled', true);
    }

    var size        = file.size;
    var chunkSize   = 2097152;//2 megabyte
    var endByte     = chunkSize + startByte;
    var isLast      = (size - endByte <= 0);
    var chunk       = file;
    var xhr         = new XMLHttpRequest();//prepare xhr for upload
    var chunkNum    = endByte / chunkSize;

    if(chunkSize == 0)//no divide
    {
        chunk   = file;
        isLast  = true;
    }
    else if(file.mozSlice) // moz slice
    {
        chunk   = file.mozSlice(startByte, endByte);
    }
    else if(file.webkitSlice) //webkit slice
    {
        chunk   = file.webkitSlice(startByte, endByte);
    }
    else if(file.slice) // w3c slice
    {
        chunk   = file.slice(startByte, chunkSize);
    }
    else
    {
        chunk   = file;
        isLast  = true;
    }

    //progress function, with ajax upload progress can be monitored
    xhr.upload.addEventListener('progress', function(e)
    {
        if (e.lengthComputable) 
        {
            var perc = Math.round((e.loaded + chunkNum * chunkSize - chunkSize) * 100 / size);
            //console.log(perc+':'+index);
            $('#progress'+index).progressbar("option", "value", perc);
        }  
    }, false); 

    xhr.upload.onabort=function(e)  {   
        finishUp(index,'Aborted');
    };  

    xhr.upload.addEventListener('error', function(e){
        finishUp(index, this.responseText+'--->'+name);
    }, false);  

    xhr.onreadystatechange=function()
    {
        if(this.readyState == 4 && this.status == 200)
        {
            try
            {
                var ret = JSON.parse(this.responseText);

                if(isLast)
                {
                    finishUp(index,'');
                }
                else if(ret.status == 'error')
                {
                    throw ret.info;
                }
                else
                {
                    uploadAjax(file, endByte, index);
                }
            }
            catch(err)
            {
                finishUp(index, err);
            }

            delete chunk;
        }
    };

    var path    = get_final_path();
    var url     = "filetransfer/uploadfiles.php?ax-file-name="+encodeURIComponent(file.name)+"&ax-file-path="+encodeURIComponent(path)+'&ax-start-byte='+startByte;

    xhr.open("POST", url, true);
    xhr.setRequestHeader('Cache-Control', 'no-cache');
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');//header
    xhr.setRequestHeader('Content-Type', 'application/octet-stream');//generic stream header

    /*var reader = new FileReader();
    reader.onload = function(evt) {  
        xhr.sendAsBinary(evt.target.result);  
    };  
    reader.readAsBinaryString(chunk);
    */  
    xhr.send(chunk);

    return xhr;
}

有哪些地方可以进行优化或释放对象?


你试过关闭标签页吗?版本是多少? - nhahtdh
2
很遗憾,你只能访问about:memory - Rob W
Ajax文件上传器?听起来非常有趣(这里是讽刺)。至于你的问题:不可能。 - freakish
Firefox的版本从5到13。 - albanx
@albanx 你必须清除所有对此数据的引用。如果你有很多作用域,那么这可能不是一项容易的任务(在某些情况下可能是不可能的)。只有这样,浏览器才会释放内存(至少在某个时候)。顺便说一句:你那里有一个相当有趣的库。我稍后会看一下。记住,通过AJAX上传文件是不可能的(除非浏览器支持HTML5)。那他们如何使其与旧版浏览器兼容呢?通常都是使用iframe的一些技巧。这可能与你的问题有关。 - freakish
我现在正试图使用“delete object”来完成这个操作。 - albanx
4个回答

2
我使用Memoryfox插件将Firefox的内存保持到最小。虽然我只在浏览器中使用它(不启用“所有进程”选项),因为我经常运行Photoshop/Lightroom,而在所有进程模式下它往往会干扰它们(它非常激进)。 Memory Fox 即使如此,Firefox仍然会膨胀。最好的方法是删除您不使用的任何插件并禁用您不经常使用的插件。如果您有很多插件,则其中一些会导致Firefox出现严重的内存问题,其中一些在MemShrink project下得到了突出显示。
特别是关于您编辑中提供的代码,您可能会看到额外的内存使用原因有几个:
1)使用匿名函数意味着每次运行uploadAjax时都会在内存中创建一个新函数。将您的函数定义在uploadAjax之外,然后引用它们以避免在内存中重复。
2)完成后使用delete xhr;。通常情况下不需要,但如果您执行大量上传,则可能会留下一些东西。
3)您本质上是在递归调用和匿名函数内部调用uploadAjax(file, endByte, index);,这意味着您在高级别调用中创建的所有内容可能仍然存在,而低级别调用执行。这将导致多个内存中的xhrchunk。考虑以不同的方式调用uploadAjax(例如通过触发事件然后从全局访问相同的文件和xhr,或在短时间内启动计时器以引入执行断开连接。我可能更喜欢前者,但没有自己测试很难说)。

问题在于我正在开发这个上传器,我不希望它发生在客户端浏览器中,而是在我的浏览器中。 - albanx
哦,这很不错。看起来甚至还集成了我在回答中提到的about:memory中的那些功能。 - JAB
在客户端浏览器中,您无法控制内存使用情况,这取决于他们如何管理内存。在浏览器中运行的受限范围意味着您必须接受其浏览器所做的任何事情。但是,您可以在上传脚本中采取各种步骤来清理自己。确保您明确地“删除”不再需要的任何内容,以便您不会留下垃圾供GC忽略。 - Bob Davies
仅返回翻译后的文本:添加了关于问题作者所编辑的特定代码的详细信息 - Bob Davies

1

这不是你想要的,但听起来这就是你需要的:

https://addons.mozilla.org/en-US/firefox/addon/memory-restart/

您可以为警报设置阈值,甚至可以自动重新启动。

(尽管我刚刚在Rob W的帮助下发现,about:memory允许您进行垃圾回收和其他内存清理(至少在Firefox 13中是这样;我没有检查它能够向后兼容多少版本,因为我没有在这台机器上安装以前的Firefox版本,并且我真的没有时间下载和安装以前的版本来测试)。非常棒。即使不是自动的,如果您不喜欢Firefox的自动重新启动功能,您可能想先尝试使用它。)


问题在于我正在开发这个上传器和一些Web应用程序,我不希望这个问题发生在客户浏览器中,也不希望在我的浏览器中出现。 - albanx

0

这是Firefox背后最糟糕的事情...我以前也遇到过这个问题。问题在于你必须重新启动浏览器,这样一些内存就会被释放,但不是全部。这是单页应用程序的主要问题,因为它主要使用DOM替换而不刷新页面。


这正是我所面临的问题,因此我担心使用我的 Web 应用程序的用户。 - albanx
这是单页应用程序的主要问题,而且很难解决。你必须清除所有停止使用的DOM,而不仅仅是隐藏和显示。 - Someth Victory

0

在Firefox中,没有JavaScript API可以帮助解决您的问题。尽管我们进行了大量工作来改善Firefox的占用空间,但内存使用一直是最长期的投诉之一。您的选择主要有:

(a)重启Firefox以杀死进程并释放其分配的内存

(b)使用第三方工具或插件,无论是针对Firefox还是Windows,以帮助释放其中的一些内存

(c)使用其他浏览器,例如Chrome,它使用每个标签页一个进程模型,有助于缓解内存使用方面的问题

顺便说一下 - 这里有来自Mozilla知识库的更多信息


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