我有一个示例web-worker画布更新脚本正在运行,但我注意到它每隔几秒就会停止大约200ms.通常的循环时间约为15ms.
我猜这是垃圾收集 - 它看起来像是分析器.
http://codepen.io/SarahC/pen/bgBoMM
我认为这是在这个功能:
function nextFrame(){ timeChart.start(); workersWorking = workerCount; var stripHeight = ~~( h / workerCount ); for(var i = 0; i < workerCount; i++){ var localImageData = ctx.getImageData(0, stripHeight * i, w, stripHeight); /// This needs putting in constant memory.... GC takes ages here. workers[i].postMessage({imageData: localImageData, YPosition: stripHeight * i, threadNumber: i}); } }
如果这个位正在制作所有的垃圾内存,我不知道我能做些什么来继续为这些数据块使用相同的内存区域.
这样,您的缓冲区就会被传输(使用零复制操作),并且不会再污染主线程的内存.
否则,当您不传输它时,您的对象将被结构化克隆(就像您一样JSON.parse(JSON.stringify(yourObject));
),这意味着当您从工作程序发送回主线程时,计算机将三个相同数据的副本保存在内存中.
请注意,当在worker中传递时,imageData的数据在主线程中不再可用(如果你尝试putImageData()它会抛出一个错误).遗憾的是我不知道改变ImageData缓冲区的好方法,但是你可以在创建时设置一个缓冲区,这要归功于ImageData()
构造函数(显然在IE中仍然不支持...),这确实只是创建一个指针到arrayBuffer.
所以当支持所有这些时,只{width:XXX, height:XXX}
创建ImageData结构(基本上是一个对象)而不是重缓冲区.其他所有东西都被移动了,不会污染记忆.
let workerURL = URL.createObjectURL(new Blob([workerScript.textContent], {
type: 'application/javascript'
}));
const worker = new Worker(workerURL);
worker.onmessage = e => {
let buf = e.data,
arr = new Uint8ClampedArray(buf),
processedImageData;
try {
processedImageData = new ImageData(arr, imageData.width, imageData.height);
} catch (e) {
processedImageData = ctx.createImageData(imageData.width, imageData.height);
processedImageData.data.set(arr);
}
// checks that we didn't created an useless buffer in this last step
// IE will because it doesn't support new ImageData(buf)
console.log('Does our TypedArray share the same buffer as the one we received ? ',
arr.buffer === buf);
console.log('Does our new imageData share the same buffer as the one we received ? ',
processedImageData.data.buffer === buf);
// Note that here a check for the original imageData's buffer has no sense
// since it has been emptied
ctx.putImageData(processedImageData, 0, 0);
}
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
ctx.fillRect(20, 20, 60, 80);
let imageData = ctx.getImageData(0, 0, 300, 150);
// pass it as transferable
worker.postMessage(imageData.data.buffer, [imageData.data.buffer]);
console.log(imageData.data.length, 'now empty')