canvas.getImageData + canvas.putImageData的性能问题

Ale*_*exD 7 javascript google-chrome canvas heatmap leaflet

我正在调用getImageData/putImageData,它会导致我的Chrome进程填满,直到它达到2.5Gb内存时崩溃.

我正在使用带有传单热图插件的simpleheat.js来在画布上显示热图.

基本上,我正在调用绘图fn以建立"随时间变化的热图"效果.我处理每个运行的数据(每个getImageData/putImageData)是4Mb,而以10-20 fps调用.

我想知道如何优化这段代码.我对使用画布知之甚少.

这是相关的代码simpleheat.js:

draw: function() {
    ...
    var colored = ctx.getImageData(0, 0, this._width, this._height);
    this._colorize(colored.data, this._grad);
    ctx.putImageData(colored, 0, 0);
},
_colorize: function (pixels, gradient) {
    for (var i = 0, len = pixels.length, j; i < len; i += 4) {
        j = pixels[i + 3] * 4; // get gradient color from opacity value

        if (j) {
            pixels[i] = gradient[j];
            pixels[i + 1] = gradient[j + 1];
            pixels[i + 2] = gradient[j + 2];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我试过减少DOM访问(在另一个问题中建议)

var colored = ctx.getImageData(0, 0, this._width, this._height);
var coloredData = colored.data;
this._colorize(coloredData, this._grad);
colored.data = coloredData;
ctx.putImageData(colored, 0, 0);
Run Code Online (Sandbox Code Playgroud)

我认为问题是浏览器没有正确释放4Mb的数据,因为如果我保持页面一段时间内存最终会丢失

我尝试过一些愚蠢的尝试来帮助GC释放数据阵列(colored.data = nullundefined)

小智 0

创建 ctx 时,您可以为其指定一个属性,以使这些操作更快。

const ctx = canvas.getContext("2d", { willReadFrequently: true }); 有关 willReadFrequently 的更多信息:HTML willReadFrequently 规范(如果您滚动浏览,还有一些有关画布的其他花絮,可能对性能有用)

另外,如果可能,请避免每帧运行 getImageData。如果有一种方法可以在不获取每个像素值的情况下获取渐变的不透明度值,那么您可以拥有一张可以更改并放置每一帧的图像。

您也可以完全忘记这个方法并使用 gpu.js 执行相同的操作,从实现来看这不会太困难。