繁体   English   中英

在将文件写入客户端磁盘时从 blob 创建/对象 URL 释放内存

[英]Releasing memory from blob creation / object URL in writing file to client's disk

更新

由于在发现代码中的错误后提出了下面的问题并得出了一个更基本的问题,因此我发现了更多信息,例如在 MDN 网络文档中下载 API 方法 downloads.download() 它指出撤销对象url 应仅文件/url 下载执行。 因此,我花了一些时间试图了解网络扩展是否使下载 API onChanged 事件对网页的 javascript“可用”,但我认为它不会。 我不明白为什么下载 API 仅可用于扩展,尤其是当有很多关于相同内存使用/对象 URL 撤销问题的问题时。 例如, 等待用户完成 Javascript 中的 blob 下载

如果你知道,请你解释一下? 谢谢你。


从关闭 Firefox 浏览器开始,右键单击本地 html 文件以在 Firefox 中打开,它打开时会在 Windows 任务管理器中看到五个 firefox.exe 进程。 其中四个进程的内存在 20,000k 到 25,000k 之间,一个进程的内存约为 115,000k。

这个 html 页面有一个 indexedDB 数据库,其中有 50 个对象存储,每个存储包含 50 个对象。 每个对象从其对象存储中提取并使用 JSON.stringify 转换为字符串,并写入二维数组。 之后,数组的所有元素都连接成一个大字符串,转换为 blob 并通过 URL 对象写入硬盘,该对象随后立即被撤销。 最终文件大约为 190MB。

如果代码在转换为 blob 之前停止,则 firefox.exe 进程之一的内存使用量会增加到 425,000k 左右,然后在将数组元素连接成一个单字符串。

如果代码运行完成,同一个 firefox.exe 进程的内存使用量会增长到大约 1,000,000k,然后下降到大约 225,000k。 从 115,000k 开始的 firefox.exe 进程也在代码的 blob 阶段增加到大约 325,000k,并且永远不会减少。

在将 blob 作为文本文件写入磁盘后,这两个 firefox.exe 进程永远不会释放大约 2 x 200,000k 的内存增加。

我已将每个函数中使用的每个变量都设置为 null,除非刷新页面,否则永远不会释放内存。 另外,这个过程是由一个按钮点击事件发起的; 如果在没有中间刷新的情况下再次运行,这两个 firefox.exe 进程中的每一个都会在每次运行时额外占用 200,000k 内存。

我一直无法弄清楚如何释放内存?

这两个功能非常简单。 json[i][j] 保存数据库中第 i 个对象存储中的第 j 个对象的字符串版本。 os_data[] 是一个小对象数组 { "name" : objectStoreName, "count" : n },其中 n 是存储中对象的数量。 如果未调用 write_to_disk,则 build_text 功能似乎会释放内存。 因此,问题似乎与 blob 或 url 有关。

我可能忽略了一些明显的东西。 感谢您提供的任何方向。

编辑:

我从JavaScript: Create and save file看到我在 revokeObjectURL(blob) 语句中有错误。 它不能撤销blob,需要将createObjectURL(blob) 保存到一个像url 这样的变量中,然后撤销url,而不是blob。

在大多数情况下,这在大多数情况下有效,并且内存从上面提到的两个 firefox.exe 进程中释放。 这给我留下了一个关于撤销 url 时间的小问题。

如果撤销是允许释放内存的,那么只有在成功下载文件后才能撤销url吗? 如果撤销发生在用户单击确定下载文件之前,会发生什么? 假设我点击按钮从数据库准备文件,准备好后浏览器打开下载窗口,但我等了一会儿,想着给文件命名或保存在哪里,不会撤销声明已经运行,但浏览器仍然“持有”该网址,因为它将下载什么? 我知道我仍然可以下载文件,但是撤销是否仍然释放内存? 从我对这个示例的少量试验来看,它似乎不会在这种情况下发布。

如果在文件已成功或未成功下载到客户端时触发了一个事件,那不是应该撤销 url 的时间吗? 在撤销 url 之前设置几分钟的超时会更好,因为我很确定没有事件表明下载到客户端已经结束。

我可能不了解这方面的一些基本知识。 谢谢。

function build_text() {

    var i, j, l, txt = "";

    for ( i = 1; i <=50; i++ ) {

         l = os_data[i-1].count;

         for  ( j = 1; j <= l; j++ ) {

              txt += json[i][j] + '\n';

         }; // next j

    }; // next i


    write_to_disk('indexedDB portfolio', txt); 

    txt = json = null;

} // close build_text




function write_to_disk( fileName, data ) {  

    fileName = fileName.replace(".",""); 

    var blob = new Blob( [data], { type: 'text/csv' } ), elem;  


    if ( window.navigator.msSaveOrOpenBlob ) {

         window.navigator.msSaveBlob(blob, fileName);

    } else {

        elem = window.document.createElement('a');

        elem.href = window.URL.createObjectURL(blob);

        elem.download = fileName;        

        document.body.appendChild(elem);

        elem.click();        

        document.body.removeChild(elem);

        window.URL.revokeObjectURL(blob);

   }; // end if


   data = blob = elem = fileName = null;


} // close write_to_disk

我有点不明白这里的问题是什么......

但让我们试着回答,至少是其中的一部分:

首先让我们解释一下URL.createObjectURL(blob)大致做了什么:

它创建一个blob URI,这是一个URI指向一滴blob的记忆就像如果它是在到达的地方(如服务器)。
这个 blob URI 会将blob标记为垃圾收集器 ( GC ) 不可收集,只要它没有被撤销,这样您就不必在脚本中维护对blob的实时引用,但您可以仍然使用/加载它。

URL.revokeObjectURL然后将断开 blob URI 和内存中的 Blob 之间的链接。 它不会直接释放blob占用的内存,它只会删除自己对 GC 的保护,[不再指向任何地方]。
因此,如果您有多个 Blob URI 指向同一个 Blob 对象,则仅撤销一个不会破坏其他 Blob URI。

现在,只有在 GC 启动时才会释放内存,这仅由浏览器内部决定,当它认为这是最佳时间时,或者当它看到它没有其他选择时(通常是当它错过了内存空间时) )。

所以你没有看到你的内存立即被释放是很正常的,根据经验,我会说 FF 不关心使用大量内存,当它可用时,使得 GC 踢不那么频繁, whihc 有利于用户体验(GCing 通常会导致滞后)。


对于您的下载问题,实际上,Web API 没有提供一种方法来了解下载是成功还是失败,甚至是否刚刚结束。
对于撤销部分,这实际上取决于您何时执行。
如果直接在点击处理程序中进行,那么浏览器还没有完成预取请求,因此当点击(下载)的默认操作发生时,URI 将不会链接任何内容了。
现在,如果您在“保存”提示后撤销 Blob URI,浏览器将执行预取请求,因此可能能够自行标记 Blob 资源不应被清除。 但我认为这种行为不受任何规范的约束,最好至少等待窗口的focus事件,此时资源的下载应该已经开始。

 const blob = new Blob(['bar']); const uri = URL.createObjectURL(blob); anchor.href = uri; anchor.onclick = e => { window.addEventListener('focus', e=>{ URL.revokeObjectURL(uri); console.log("Blob URI revoked, you won't be able to download it anymore"); }, {once: true}); };
 <a id="anchor" download="foo.txt">download</a>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM