Утечка памяти при объединении больших двоичных объектов в более крупные, но не знаю, почему
Этот код немного странный на данный момент, потому что он нарезает медиафайл на части, считывает каждую часть как буфер массива, собирает результаты и загружает их в элемент видео; но это тест перед заменой функции fetch_video данными, подаваемыми откуда-то еще.
Мой вопрос: почему утекает память? URL-адрес объекта отменяется при нажатии кнопки. Некоторые переменные являются глобальными, но не будут таковыми, если в конечном итоге будет использован этот метод.
Когда файл открывается в средстве выбора файлов и обрабатывается, оперативная память, конечно, увеличивается, но после этого полностью не освобождается. Я пытался повторно открыть видеофайл размером 100 МБ. Каждый раз потребление оперативной памяти увеличивается примерно на 300 МБ, а после нажатия кнопки отзыва URL-адреса объекта объем оперативной памяти уменьшается примерно на 100 МБ. Таким образом, каждая итерация потребляет еще 200 МБ, которые не освобождаются. Я попытался установить для всех переменных значение null при закрытии каждой функции на случай, если некоторые ссылки были сохранены, но это не имело значения.
Не могли бы вы сказать мне, что я делаю неправильно, пожалуйста? Спасибо.
<body>
<video controls></video>
<label><input type="file"></input>Hard Drive</label>
<button>Revoke Blob URL</button>
</body>
"use strict";
var video_file, blob_url,
video_blob = new Array(),
chunk = 1024 * 1024,
video = document.body.firstElementChild;
video.nextElementSibling.addEventListener( 'change', open_file, false );
video.addEventListener( 'canplay', () => { console.log( "Video can play." ); }, false );
video.nextElementSibling.nextElementSibling.addEventListener( 'mousedown', () =>
{
video.removeAttribute( "src" );
video.load();
URL.revokeObjectURL( blob_url );
video_file = null;
}, false );
function open_file( evt )
{
video_file = evt.target.files[0];
fetch_video.remaining = video_file.size;
fetch_video.start = 0;
append_blobs();
} // close open_file
async function append_blobs()
{
var buf;
if ( fetch_video.remaining > 0 )
{
buf = await fetch_video();
if ( buf !== -1 )
{
video_blob.push( buf );
append_blobs();
}
else
console.log( "error" );
}
else
{
let v = new Blob( video_blob, { type : video_file.type } );
blob_url = URL.createObjectURL( v );
video.src = blob_url;
v = null;
};
}
function fetch_video()
{
return new Promise( ( resolve, reject ) =>
{
let f = fetch_video;
f.end = f.start + Math.min( f.remaining, chunk );
console.log( "start: " + f.start + ", end: " + f.end + ", remaining: " + f.remaining + ", end - start: " + ( f.end - f.start ) );
if ( f.remaining > 0 )
read_chunk( new Blob( [ video_file.slice( f.start, f.end ) ], { type : video_file.type } ) )
.then( ( data ) =>
{
f.remaining = video_file.size - f.end;
f.start = f.end;
resolve( data );
},
( err ) => { reject( -1 ); }
);
else
reject( - 1 );
});
} // close fetch_video
function read_chunk( blob )
{
return new Promise( ( resolve, reject ) =>
{
let reader = new FileReader();
reader.onload = () => { resolve( reader.result ); };
reader.onerror = ( e ) => { reject(); };
reader.readAsArrayBuffer( blob );
}); // close new promise
} // close read_file