Можно ли очистить память после FileReader?

FileReader, кажется, потребляет всю память, поскольку он неоднократно используется для предварительной загрузки нескольких больших двоичных объектов и никогда не освобождает ее. Любой известный способ заставить его освободить потребляемую память? Установка объекта FileReader и его свойства результата в значение null, похоже, не работает.

ОБНОВЛЕНИЕ:

Вот пример кода (протестируйте его на больших файлах, таких как фильм, иначе вы не заметите эффект в диспетчере задач):

<input id="file" type="file" onchange="sliceMe()" />

<script>
function sliceMe() {
    var file = document.getElementById('file').files[0], 
        fr,
        chunkSize = 2097152, 
        chunks = Math.ceil(file.size / chunkSize), 
        chunk = 0;

    function loadNext() {
       var start, end,
           blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice;

       start = chunk * chunkSize;
       end = start + chunkSize >= file.size ? file.size : start + chunkSize;

       fr = new FileReader;
       fr.onload = function() {      
          if (++chunk < chunks) {
             // shortcut - in production upload happens and then loadNext() is called
             loadNext(); 
          }
       };
       fr.readAsBinaryString(blobSlice.call(file, start, end));
    }

    loadNext();
}
</script>

Я пытался каждый раз создавать новый экземпляр FileReader, но проблема все еще остается. Я подозреваю, что это может быть вызвано круговым характером узора, но я не уверен, какой другой узор можно использовать в этом случае.

Я проверил этот код как в Firefox, так и в Chrome, и Chrome, похоже, справляется с ним более изящно — он очищает память после каждого цикла и работает очень быстро. Но ирония ситуации в том, что Chrome вообще не нужно использовать этот код. Это просто эксперимент по преодолению ошибки Gecko 6- FormData + Blob (Ошибка 649150 - у BLOB-объектов нет имя файла, если оно отправлено через FormData).


person jayarjo    schedule 21.08.2011    source источник
comment
Пробовали ли вы не использовать повторно средство чтения файлов, а создавать новый экземпляр каждый раз, когда оно вам нужно?   -  person Caspar Kleijne    schedule 21.08.2011
comment
У вас есть яркий пример? Какой браузер? Не могли бы вы создать скрипку?   -  person pimvdb    schedule 21.08.2011
comment
Спасибо четырем вашим примерам. Однако установка его на null, похоже, очищает память через несколько секунд (при выборе другой вкладки).   -  person pimvdb    schedule 21.08.2011
comment
Интересное наблюдение... хм. На самом деле иногда он очищает память даже без установки нуля, но с нулем дело обстоит более отчетливо. Интересно, теперь мы можем использовать это как-то...   -  person jayarjo    schedule 22.08.2011
comment
Сообщение об ошибке: bugzilla.mozilla.org/show_bug.cgi?id=680847, вы, ребята, можете проголосовать за это.   -  person jayarjo    schedule 22.08.2011


Ответы (2)


Вместо этого попробуйте так:

function sliceMe() {
        var file = document.getElementById('file').files[0],
        fr = new FileReader,
        chunkSize = 2097152,
        chunks = Math.ceil(file.size / chunkSize),
        chunk = 0;

    function loadNext() {
       var start, end,
           blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice;

       start = chunk * chunkSize;
       end = start + chunkSize >= file.size ? file.size : start + chunkSize;

       fr.onload = function() {      
          if (++chunk < chunks) {
             //console.info(chunk);
          }
       };
       fr.onloadend = function(e) {      
          loadNext(); // shortcut here
       };
       fr.readAsBinaryString(blobSlice.call(file, start, end));
    }

    loadNext();
}

Onloadend не позволит вам перекрывать другие ваши чтения... (Очевидно, вы можете исправить приращение немного лучше, но вы поняли идею...)

person Craig    schedule 31.07.2013

Ошибка была помечена как INVALID, так как оказалось, что я на самом деле неправильно повторно использовал объект FileReader.

Вот шаблон, который не загружает память и процессор:

function sliceMe() {
    var file = document.getElementById('file').files[0],
        fr = new FileReader,
        chunkSize = 2097152,
        chunks = Math.ceil(file.size / chunkSize),
        chunk = 0;

    function loadNext() {
       var start, end,
           blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice;

       start = chunk * chunkSize;
       end = start + chunkSize >= file.size ? file.size : start + chunkSize;

       fr.onload = function() {      
          if (++chunk < chunks) {
             //console.info(chunk);
             loadNext(); // shortcut here
          }
       };
       fr.readAsBinaryString(blobSlice.call(file, start, end));
    }

    loadNext();
}

Был отправлен еще один отчет об ошибке: https://bugzilla.mozilla.org/show_bug.cgi?id=681479, что связано, но не является злом в данном случае.

Спасибо Кайлу Хьюи за то, что обратил на это мое внимание :)

person jayarjo    schedule 24.08.2011
comment
Эй, это решение действительно сработало для вас ?? У меня похожая проблема, с похожей попыткой загрузки больших файлов по кусочкам. Но хром по-прежнему дает сбой или перестает отвечать на запросы при загрузке файлов размером более гигабайта. Я повторно использую объект FileReader вместо того, чтобы создавать его каждый раз. - person Roy Kachouh; 04.04.2012
comment
Вы загружаете весь файл в память? - person jayarjo; 05.04.2012
comment
Нет, я пытаюсь прочитать файл фрагментами. На самом деле, я даже пытался просто скопировать приведенный выше код. - person Roy Kachouh; 06.04.2012
comment
Я почти уверен, что вам нужен постинкремент, а не преинкремент. это (chunk++ ‹ куски) вместо (++chunk ‹ куски). - person Dave; 03.06.2013