【问题标题】:HTML5 FileReader API Memory IssuesHTML5 FileReader API 内存问题
【发布时间】:2015-06-01 00:50:06
【问题描述】:

简而言之,我使用 HTML5 FileReader API 和 xhr 帖子编写了一个文件上传器,用于将用户选择的文件上传到服务器。我的客户端代码有一些基本任务,包括从选定文件的标题(这些是 DICOM 图像文件)中获取值并在将文件发送到服务器之前显示它们,更新进度条等。我还有一些功能,包括压缩文件以加快速度等。

很快,我注意到大文件占用了 内存(Chrome 特有)。给定一个足够大的数据集,Chrome “Aw, Snap!”s 并完全崩溃。我已经实现了无数的修复:彻底搜索内存泄漏,延迟读取和使用回调和一个小队列发送文件,一次只读取每个文件的大小 n 块,等等。正如你可以想象的那样,这导致了一些相当庞大的客户端 JavaScript(实际上是咖啡脚本)。在下面的小提琴中,我和一位同事将其缩减为最基本的内容:以块的形式读取所有选定的文件并为该二进制数据设置一个变量(让每个人都阅读解析标题的代码,必要时压缩并发送每个块)。

https://jsfiddle.net/3nails4you/gsqzrk9g/8/,或见下文:

HTML:

<input id="file" type="file" onchange="slice()" multiple="" />

JavaScript:

function slice() {

    var filesArr = document.getElementById('file').files;
    var index;
    for (index = 0; index < filesArr.length; index++) {
        readFile(filesArr[index]);
    }
}

function readFile(file) {

    var fr = new FileReader(),
        chunkSize = 2097152,
        chunks = Math.ceil(file.size / chunkSize),
        chunk = 0;

    function loadNext() {
        var start, end, blob;

        start = chunk * chunkSize;
        end = start + chunkSize >= file.size ? file.size : start + chunkSize;

        fr.onload = function (e) {
            // get file content
            var filestream = e.target.result;
            if (++chunk < chunks) {
                console.info(chunk);
                loadNext();
            }
        };
        blob = file.slice(start, end);
        fr.readAsBinaryString(blob);
    }
    loadNext();
}

我尝试了不同的读取方法(如 ArrayBuffer、DataURL)、许多不同的结构以及可变范围(例如,仅声明 1 个 FileReader 并重用等),并尝试了许多不同的块大小以进行优化。当我选择一个约 1 GB 的特定数据集时,跨 16 个文件,内存使用情况如下所示:

[编辑] 我还不能发布图片,所以我只描述一下。查看Windows任务管理器,chrome进程使用625,000K内存。

值得注意的是,如果我等待读取完成(控制台日志将停止输出),内存使用量将变为静态。如果此时我打开 JavaScript 控制台,内存使用量会下降到开始读取文件之前的水平。我怀疑打开控制台的行为会触发 Chrome 的垃圾收集,或者类似的东西,但我不确定。

我发现了一些关于类似问题的其他问题,但所有问题的答案都是假设客户端实际上不需要使用文件的二进制数据。我绝对愿意 - 有什么建议吗?这仅仅是报告 Chromium 项目的错误吗?我的代码中是否有明显的错误而我只是错过了?我通常倾向于怀疑后者,但是“打开控制台清除内存”这一点继续让我感到厌烦——如果有内存泄漏,真的会这样吗?感谢阅读,感谢您的任何建议!

【问题讨论】:

  • 您可以尝试一次处理一个文件,而不是一次全部加载。您也可以尝试使用 Workers 创建一次性运行时。
  • 我一次完成了一个文件 - 问题仍然存在。我什至设置了允许在读取每个文件之间暂停 60 秒的超时 - 内存只会每 60 秒跳跃一次并且永远不会减少(就像在示例中一样,但显然速度要慢得多)。工人是一个有趣的想法 - 我以前从未与他们合作过,我要去看看!谢谢!
  • workers 有FileReaderSync(),这可能会使它变得更好,但您始终可以从worker 内部调用self.terminate() 来停止程序并恢复RAM。您还可以将文件作为 blob 传递给工作人员,因此您应该能够像以前一样做所有相同的事情。

标签: javascript html google-chrome memory filereader


【解决方案1】:

如果有人偶然发现这个问题并遇到同样的问题,我想我会分享我们的发现以缓解这种情况。

我最终购买了许可证并将plupload 合并到我的咖啡脚本中。这有助于以这种方式解决内存问题:

首先,我创建一个新的 plupload 对象,并设置它的事件处理程序(BeforeUpload、UploadProgress 等)。它的'Destroy' 处理程序调用一个javascript 函数nextUploader(),它创建另一个上传器对象并将下一部分文件排队。销毁发生后,plupload对象的内存使用被成功回收,使得浏览器的内存使用保持在合理的范围内。

如果有人想进行 HTML5 文件读取和上传,我强烈建议您探索 plupload - 它非常易于使用,我们发现 Dropbox 也在使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2015-10-24
    • 1970-01-01
    相关资源
    最近更新 更多