Освобождение памяти от создания блоба / URL объекта при записи файла на диск клиента - PullRequest
0 голосов
/ 04 июня 2018

Обновление

Поскольку, задавая вопрос ниже и получив более фундаментальный вопрос после обнаружения ошибки в коде, я нашел дополнительную информацию, такую ​​как в веб-документах по MDN дляМетод API downloads downloads.download () указывает, что отзыв URL-адреса объекта должен выполняться только после загрузки файла / URL-адреса.Итак, я потратил некоторое время, пытаясь понять, делает ли веб-расширение событие onChanged API загрузки «доступным» для javascript веб-страницы, и не думаю, что это так.Я не понимаю, почему API-интерфейс загрузок доступен только для расширений, особенно когда возникает довольно много вопросов, касающихся этой же проблемы с использованием памяти / объектом-URL-отзывом.Например, Подождите, пока пользователь закончит загрузку BLOB-объекта в Javascript .

Если вы знаете, не могли бы вы объяснить?Спасибо.


Начиная с закрытого браузера Firefox и щелкая правой кнопкой мыши локальный html-файл, чтобы открыть его в Firefox, он открывается пятью процессами firefox.exe, как показано в диспетчере задач Windows.Четыре из этих процессов начинаются с объема памяти от 20 000 до 25 000 КБ, а один - с 115 000 КБ.

На этой html-странице имеется база данных indexedDB с 50 хранилищами объектов, в каждом из которых содержится 50 объектов.Каждый объект извлекается из его хранилища объектов и преобразуется в строку с помощью JSON.stringify и записывается в двумерный массив.После этого все элементы массива объединяются в одну большую строку, преобразуются в большой двоичный объект и записываются на жесткий диск через объект URL, который сразу же отзывается.Окончательный размер файла составляет около 190 МБ.

Если код останавливается непосредственно перед преобразованием в BLOB-объект, использование памяти одним из процессов firefox.exe увеличивается примерно до 425 000 КБ, а затем уменьшается до 25 000 К примерно через 5-Через 10 секунд после того, как элементы массива были объединены в одну строку.

Если код выполняется до конца, использование памяти тем же процессом firefox.exe возрастает примерно до 1 000 000 К, а затем падает примерно до225,000k.Процесс firefox.exe, который начался на 115 000 КБ, также увеличивается на этапе создания большого двоичного кода до 325 000 КБ и никогда не уменьшается.

После того, как большой двоичный объект записан на диск в виде текстового файла, эти два файла firefox.exeпроцессы никогда не освобождают приблизительное увеличение памяти в 2 x 200 000 тыс.

Я установил для каждой переменной, используемой в каждой функции, значение NULL, и память никогда не освобождается, если страница не обновлена.Кроме того, этот процесс инициируется событием нажатия кнопки;и если он запускается снова без промежуточного обновления, каждый из этих двух процессов firefox.exe захватывает дополнительно 200 000 КБ памяти при каждом запуске.

Я не смог выяснить, как освободить память?

Две функции довольно просты.json [i] [j] содержит строковую версию j-го объекта из i-го хранилища объектов в базе данных.os_data [] - это массив небольших объектов {"name": objectStoreName, "count": n}, где n - количество объектов в хранилище.Функция build_text освобождает память, если write_to_disk не вызывается.Итак, проблема, кажется, связана с BLOB-объектом или URL-адресом.

Я, вероятно, упускаю из виду нечто очевидное.Спасибо за любое направление, которое вы можете указать.

РЕДАКТИРОВАТЬ:

Я вижу из JavaScript: создайте и сохраните файл , в котором у меня ошибкаоценка revokeObjectURL (blob).Он не может отозвать blob, createObjectURL (blob) нужно было сохранить в переменную типа url, а затем отозвать url, а не blob.

Это сработало по большей части, и в большинстве случаев освобождается память от обоих процессов firefox.exe, упомянутых выше.Это оставляет мне один маленький вопрос о сроках отзыва URL.

Если отмена - это то, что позволяет освободить память, должен ли отзываться 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

1 Ответ

0 голосов
/ 05 июня 2018

Я немного растерялся, что за вопрос здесь ...

Но давайте попробуем ответить, хотя бы частично:

Для начала давайте объясним, что URL.createObjectURL(blob) примерно делает:

Создает URI BLOB-объекта, который представляет собой URI, указывающий на BLOB-объект blob в памяти, как если бы он находился в доступном месте (например, на сервере).
Этот URI BLOB-объектапометит blob как недоступный для сбора сборщиком мусора ( GC ) до тех пор, пока он не был отозван, так что вам не придется поддерживать прямую ссылку на blob вваш сценарий, но вы все еще можете использовать / загрузить его.

URL.revokeObjectURL затем разорвет связь между URI BLOB и BLOB в памяти.Он не освободит память, занятую blob напрямую, он просто снимет свою собственную защиту относительно GC, [и больше не будет указывать куда-либо].
Так что, если у вас есть несколько URI большого двоичного объекта, указывающих на один и тот жеОбъект BLOB, отмена только одного, не сломает URI другого BLOB-объекта.

Теперь память будет освобождена только при включении GC, и это решается только внутренними компонентами браузера, когда он думает, что этоэто лучшее время, или когда он видит, что у него нет других вариантов (как правило, когда он пропускает пространство памяти).

Так что вполне нормально, что вы не видите, что ваша память освобождается мгновенно и опытным путемЯ бы сказал, что FF не заботится об использовании большого количества памяти, когда она доступна, что заставляет GC пинать не так часто, что хорошо для пользовательского опыта (GCing часто приводит к задержкам).


На ваш вопрос о загрузке, действительно, веб-API не предоставляют способ узнать, была ли загрузка успешной или неудачной, и даже если она только что закончилась.
Для отзывачастично, это действительно зависит от того, когда вы это сделаете.
Если вы сделаете это непосредственно в обработчике кликов, то браузер еще не выполнит запрос на предварительную выборку, поэтому, когда действие щелчка по умолчанию (загрузка), больше ничего не будет связано с URI.
Теперь, если вы отмените URI BLOB-объекта после запроса «сохранить», браузер выполнит запрос предварительной выборки, и, следовательно, можетв состоянии отметить, что ресурс 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>
...