title: Releasing memory from blob creation / object URL in writing file to client's disk
body: <p><strong>Update</strong></p>
  
  <p>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 <em>after</em> 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, <a href="https://stackoverflow.com/questions/29200256/wait-for-user-to-finish-downloading-a-blob-in-javascript?rq=1">Wait for user to finish downloading a blob in Javascript</a>.</p>
  
  <p>If you know, would you please explain?  Thank you.</p>
  
  <hr>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>I haven't been able to figure out how to free the memory? </p>
  
  <p>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.</p>
  
  <p>I'm probably overlooking something obvious.  Thank you for any direction you can provide.</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>I see from <a href="https://stackoverflow.com/questions/13405129/javascript-create-and-save-file">JavaScript: Create and save file</a> 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. </p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>I'm probably not understanding something basic about this.  Thanks.</p>
  
  <pre><code>function build_text() {
  
      var i, j, l, txt = "";
  
      for ( i = 1; i &lt;=50; i++ ) {
  
           l = os_data[i-1].count;
  
           for  ( j = 1; j &lt;= 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
  </code></pre>