在将文件写入客户端磁盘时从blob创建/对象URL释放内存 [英] Releasing memory from blob creation / object URL in writing file to client's disk

查看:45
本文介绍了在将文件写入客户端磁盘时从blob创建/对象URL释放内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新

由于询问了以下问题,并在发现代码错误后得出了一个更基本的问题,因此我在MDN网络文档中找到了更多信息,例如downloads API方法downloads.download()指出已撤销在下载文件/URL后,仅在 后执行对象URL.因此,我花了一些时间试图了解Web扩展是否使下载API onChanged事件可用"到网页的javascript中,并且认为它不起作用.我不明白为什么downloads API仅适用于扩展,特别是当有很多关于此相同的内存使用/对象URL吊销问题的问题时.例如,等待用户完成下载Java语言中的Blob .

Since asking the question below and arriving at a more fundamental question after finding the error in the code, I found some more information such as in the MDN web docs for the downloads API method downloads.download() it states that a revoke of an object url should be performed only after the file/url has been downloaded. So, I spent some time trying to understand whether or not a web extension makes the downloads API onChanged event 'available' to javascript of a web page and don't think it does. I don't understand why the downloads API is available to extensions only, especailly when there are quite a few questions concerning this same memory-usage/object-url-revocation issue. For example, Wait for user to finish downloading a blob in Javascript.

如果您知道,请解释一下吗?谢谢.

If you know, would you please explain? Thank you.

首先关闭Firefox浏览器,然后右键单击本地html文件以在Firefox中打开,然后打开该窗口,其中包含五个firefox.exe进程(在Windows任务管理器中查看).其中四个进程的起始内存在20,000k至25,000k之间,而另一个大约115,000k.

Starting with Firefox browser closed, and right clicking on a local html file to open in Firefox, it opens with five firefox.exe processes as viewed in Windows Task Manager. Four of the processes start with between 20,000k and 25,000k of memory and one with about 115,000k.

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

This html page has an indexedDB database with 50 object stores each containing 50 objects. Each object is extracted from its object store and converted to string using JSON.stringify, and written to a two-dimensional array. Afterward, all elements of the array are concatenated into one large string, converted to a blob and written to the hard disk through a URL object which is revoked immediately afterward. The final file is about 190MB.

如果在转换为Blob之前停止了代码,则firefox.exe进程之一的内存使用量将增加到大约425,000k,然后在数组元素被放置大约5-10秒后又下降到25,000k.连接成一个字符串.

If the code is stopped just before the conversion to blob, one of the firefox.exe process's memory usage increases to around 425,000k and then falls back to 25,000k in about 5-10 seconds after the elements of the array have been concatenated into a single string.

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

If the code is run to completion, the memory usage of that same firefox.exe process grows to about 1,000,000k and then drops to about 225,000k. The firefox.exe process that started at 115,000k also increases at the blob stage of the code to about 325,000k and never decreases.

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

After the blob is written to disk as a text file, these two firefox.exe processes never release the approximate 2 x 200,000k increase in memory.

我已将每个函数中使用的每个变量都设置为null,并且除非刷新页面,否则永远不会释放内存.同样,此过程是通过按钮单击事件启动的.如果再次运行而没有中间刷新,则这两个firefox.exe进程中的每个进程每次运行都会获取额外的200,000k内存.

I have set every variable used in each function to null and the memory is never freed unless the page is refreshed. Also, this process is initiated by a button click event; and if it is run again without an intermediate refresh, each of these two firefox.exe processes grab an additional 200,000k of memory with each run.

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

I haven't been able to figure out how to free the memory?

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

The two functions are quite simple. json[i][j] holds the string version of the jth object from the ith object store in the database. os_data[] is an array of small objects { "name" : objectStoreName, "count" : n }, where n is the number of objects in the store. The build_text fuction appears to release the memory if write_to_disk is not invoked. So, the issue appears to be related to the blob or the url.

我可能忽略了一些显而易见的事情.感谢您提供的任何指导.

I'm probably overlooking something obvious. Thank you for any direction you can provide.

我从 JavaScript:创建和保存文件中发现自己输入了错误revokeObjectURL(blob)语句.它无法撤消blob,需要将createObjectURL(blob)保存到类似url的变量中,然后撤消url,而不是blob.

I see from JavaScript: Create and save file that I have a mistake in the revokeObjectURL(blob) statment. It can't revoke blob, the createObjectURL(blob) needed to be saved to a variable like url and then revoke url, not blob.

在大多数情况下,这种方法大部分都是有效的,并且内存是从上述两个firefox.exe进程中释放的.这给我留下了一个有关撤销URL的时间的小问题.

That worked for the most part and the memory is released from both of the firefox.exe processes mentioned above, in most cases. This leaves me with one small question about the timing of the revoke of the url.

如果撤销是为了释放内存,那么是否应该仅在成功下载文件后才撤销URL?如果撤消发生在用户单击确定"下载文件之前,那么会发生什么情况?假设我单击按钮以从数据库准备文件,并且准备好浏览器后打开了下载窗口,但是我稍等了一下文件名或保存位置,就不会撤销声明了.已被运行,但浏览器仍将保留"该网址,因为它将被下载吗?我知道我仍然可以下载文件,但是撤销是否仍释放内存?从我对这个示例的少量试验中,似乎并没有在这种情况下发布它.

If the revoke is what allows for the release of memory, should the url be revoked only after the file has been successfully downloaded? If the revoke takes place before the user clicks ok to download the file, what happens? Suppose I click the button to prepare the file from the database and after it's ready the browser brings up the window for downloading, but I wait a little while thinking about what to name the file or where to save it, won't the revoke statment be run already but the url is still 'held' by the browser since it is what will be downloaded? I know I can still download the file, but does the revoke still release the memory? From my small amount of experimenting with this one example, it appears that it does not get released in this scenario.

如果有一个事件在文件成功或未成功下载到客户端时触发,那不是应该取消该URL的时间吗?最好在取消网址之前先设置几分钟的超时时间,因为我敢肯定没有事件表明下载到客户端已经结束.

If there was an event that fires when the file has either successfully or unsuccessfully been downloaded to the client, is not that the time when the url should be revoked? Would it be better to set a timeout of a few minutes before revoking the url, since I'm pretty sure there is not an event indicating download to client has ended.

我可能对此并不了解一些基本知识.谢谢.

I'm probably not understanding something basic about this. Thanks.

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

推荐答案

我对这里的问题有点迷茫...

I am a bit lost as to what is the question here...

但是让我们尝试回答至少一部分:

But let's try to answer, at least part of it:

首先,让我们解释一下 URL.createObjectURL(blob)的大致作用:

For a starter let's explain what URL.createObjectURL(blob) roughly does:

它创建一个blob URI,这是一个指向内存中Blob blob 的URI,就像它位于可访问的位置(例如服务器)一样.
只要未撤消,此blob URI就会将 blob 标记为垃圾收集器( GC )无法收集,因此您不必在脚本中维护对 blob 的实时引用,但是您仍然可以使用/加载它.

It creates a blob URI, which is an URI pointing to the Blob blob in memory just like if it was in an reachable place (like a server).
This blob URI will mark blob as being un-collectable by the Garbage Collector (GC) for as long as it has not been revoked, so that you don't have to maintain a live reference to blob in your script, but that you can still use/load it.

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

URL.revokeObjectURL will then break the link between the blob URI and the Blob in memory. It will not free up the memory occupied by blob directly, it will just remove its own protection regarding the GC, [and won't point to anywhere anymore].
So if you have multiple blob URI pointing to the same Blob object, revoking only one won't break the other blob URIs.

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

Now, the memory will be freed only when the GC will kick in, and this in only decided by the browser internals, when it thinks it is the best time, or when it sees it has no other options (generally when it misses memroy space).

因此,您通常不会看到立即释放内存,这是很正常的,根据经验,我想说FF不在乎使用大量内存(如果可用),因此不会导致GC踢因此,这经常有利于用户体验(GCing通常会导致滞后).

So it is quite normal that you don't see your memory being freed up instantly, and by experience, I would say that FF doesn't care about using a lot of memory, when it is available, making GC kick not so often, whihc is good for user-experience (GCing often results in lags).

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

For your download question, indeed, web APIs don't provide a way to know if a download has been successful or failed, nor even if it has just ended.
For the revoking part, it really depends on when you do it.
If you do it directly in the click handler, then the browser won't have done the pre-fetch request yet, so when the default action of the click (the download) will happen, there won't be anything linked by the URI anymore.
Now, if you do revoke the blob URI after the "save" prompt, the browser will have done a pre-fetch request, and thus might be able to mark by itself that the Blob resource should not be cleared. But I don't think this behavior is tied by any specs, and it might be better to wait at least for the window's focus event, at which point the downloading of the resource should already have started.

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>

>

这篇关于在将文件写入客户端磁盘时从blob创建/对象URL释放内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆