Web Worker 消耗大量内存
Web Worker consumes massive amount of memory
我正在尝试提高我的应用程序的性能,该应用程序比较两个大画布的内容。
问题是在比较期间浏览器的主线程被阻塞导致无响应UI。比较函数的执行时间大约需要 10 毫秒,并且每 250 毫秒或 500 毫秒进行一次比较。
为了解决这个问题,我想到了通过创建 web worker
使用另一个线程的想法。它现在工作得很好,但我意识到它消耗了大量的内存(在 FF 中高达 600MB,Chrome - 在 Edge 中它高达 70MB,在所有浏览器的单线程版本中它从未达到 100MB)。
我以为我留下了一些引用,垃圾收集器无法释放内存。然而,一段时间后(一整天将我的应用程序剥离并尝试 delete
、null
或 undefined
variables/data)我在下面创建了 fiddle我发送了 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);
编辑:
我发现,如果我每 n 次重复终止 worker 并创建新的 worker 就会更快地释放内存。但它仍然不是一个解决方案,只是一个古玩。
我发现如果我 运行 从开发人员工具 -> 时间轴手动垃圾收集器,它会清除所有内存。同样,如果我开始从控制台与 Worker 上下文交互,调用函数似乎会随机触发成功的 gc。
基于此,我会说不存在挂起引用,但通过传输接收对象可能不会像新分配请求那样强制执行 gc 检查。
通过响应将对象传回似乎可以解决问题:
postMessage('hi', [ev.data]); // process usage stays around 50MB
作为替代方案,确保 Worker 是重要的并且需要进行正常分配似乎也可以正确触发 gc,即:
postMessage('hi');
var twoMB = new ArrayBuffer(8388608); // usage cycles 70MB - ~220MB
我正在尝试提高我的应用程序的性能,该应用程序比较两个大画布的内容。
问题是在比较期间浏览器的主线程被阻塞导致无响应UI。比较函数的执行时间大约需要 10 毫秒,并且每 250 毫秒或 500 毫秒进行一次比较。
为了解决这个问题,我想到了通过创建 web worker
使用另一个线程的想法。它现在工作得很好,但我意识到它消耗了大量的内存(在 FF 中高达 600MB,Chrome - 在 Edge 中它高达 70MB,在所有浏览器的单线程版本中它从未达到 100MB)。
我以为我留下了一些引用,垃圾收集器无法释放内存。然而,一段时间后(一整天将我的应用程序剥离并尝试 delete
、null
或 undefined
variables/data)我在下面创建了 fiddle我发送了 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);
编辑:
我发现,如果我每 n 次重复终止 worker 并创建新的 worker 就会更快地释放内存。但它仍然不是一个解决方案,只是一个古玩。
我发现如果我 运行 从开发人员工具 -> 时间轴手动垃圾收集器,它会清除所有内存。同样,如果我开始从控制台与 Worker 上下文交互,调用函数似乎会随机触发成功的 gc。
基于此,我会说不存在挂起引用,但通过传输接收对象可能不会像新分配请求那样强制执行 gc 检查。
通过响应将对象传回似乎可以解决问题:
postMessage('hi', [ev.data]); // process usage stays around 50MB
作为替代方案,确保 Worker 是重要的并且需要进行正常分配似乎也可以正确触发 gc,即:
postMessage('hi');
var twoMB = new ArrayBuffer(8388608); // usage cycles 70MB - ~220MB