【发布时间】: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