Web Worker потребляет огромное количество памяти
Я пытаюсь улучшить производительность в своем приложении, которое сравнивает содержимое двух больших холстов.
Проблема заключается в том, что во время сравнения основной поток браузера блокируется, что приводит к невосприимчивому пользовательскому интерфейсу. Время выполнения функции сравнения занимает около 10 мс, а сравнение происходит каждые 250 мс или 500 мс.
Чтобы решить эту проблему, я придумал использовать другой поток, создав web worker
. Сейчас он работает довольно хорошо, но я понял, что он потребляет безумный объем памяти (до 600 МБ в FF и Chrome - в Edge до 70 МБ, он никогда не достигал 100 МБ в однопоточной версии во всех браузерах).
Я думал, что оставил некоторые ссылки, и Garbage Collector не может освободить память. Однако через некоторое время (целый день снятия моего приложения с фрагментов и попыток delete
, null
или undefined
переменных/данных) я создал скрипку ниже, в которой я отправляю 1MB ArrayBuffer
(хотя Я передал его, передав), но без обработки, и, как вы видите, он также потребляет огромное количество памяти.
Любые идеи, как я могу решить эту проблему (любые альтернативные решения или любые возможные улучшения работника) и где проблема?
var sortFilterDataWorker = function () {
onmessage = function image2compare(ev) {
postMessage('hi');
};
}.toString();
/* PREPARE WORKER AS STRING TO CREATE JS BLOB FILE */
sortFilterDataWorker = sortFilterDataWorker.slice(sortFilterDataWorker.indexOf('{') + 1, -1).trim();
var blob = new Blob([sortFilterDataWorker]) // create blob file with worker code
, blobUrl = window.URL.createObjectURL(blob) // create pseudo url to blob file
, compareWorker = new Worker(blobUrl)
;
setInterval(function(){
var oneMB = new ArrayBuffer(8388608);
compareWorker.postMessage(oneMB, [oneMB]); // transpile ArrayBuffer
}, 250);
FIDDLE
EDIT:
Я узнал, что если я прекращаю работу, то каждый n повторяет и создает новую, быстрее выпускает память. Но это еще не решение, просто курио.
Ответы
Ответ 1
Я обнаружил, что если я запускаю сборщик мусора вручную из инструментов разработчика → Timeline, он очищает всю память. Точно так же, если я начну взаимодействовать с контекстом Worker с консоли, вызывающие функции, похоже, случайным образом запускают успешный gc.
Основываясь на этом, я бы сказал, что нет ссылки на зависание, но получение объектов через передачу может не привести к проверке gc в качестве новых запросов на распределение.
Перенос объекта обратно с ответом, похоже, обходит проблему:
postMessage('hi', [ev.data]); // process usage stays around 50MB
В качестве альтернативы, убедитесь, что Рабочий является нетривиальным и ему нужно будет делать нормальные распределения, также, похоже, правильно запускает gc, i.e:
postMessage('hi');
var twoMB = new ArrayBuffer(8388608); // usage cycles 70MB - ~220MB
Ответ 2
Не забудьте прекратить работника после использования, вызвав: worker.terminate()
Это вызвало правильное GC по крайней мере в Safari, который также имел проблемы с памятью.