Javascript getImageData内存泄漏?

Javascript getImageData内存泄漏?,javascript,canvas,memory-leaks,getimagedata,Javascript,Canvas,Memory Leaks,Getimagedata,背景:在过去的一周里,我一直在开发一款基本上是多向的游戏,使用画布和JavaScript。我选择不清除画布上的每一帧,这样我的小线段就会留下一条轨迹。对于碰撞检测,我使用以下功能: // 8 sensors for collision testing, positioned evenly around the brush point var detectionRadius = this.width / 2 + 1; //points just outside the circumference

背景:在过去的一周里,我一直在开发一款基本上是多向的游戏,使用画布和JavaScript。我选择不清除画布上的每一帧,这样我的小线段就会留下一条轨迹。对于碰撞检测,我使用以下功能:

// 8 sensors for collision testing, positioned evenly around the brush point
var detectionRadius = this.width / 2 + 1; //points just outside the circumference
var counter = 0;
var pixelData;
for (var i = 0; i < 16; i += 2) {
    //collisionPixels[] is an array of 8 (x, y) offsets, spaced evenly around the center of the circle
    var x = this.x + collisionPixels[i] * detectionRadius;
    var y = this.y + collisionPixels[i + 1] * detectionRadius;
    pixelData = context.getImageData(x,y,1,1).data; //pixel data at each point
    if (pixelData[3] != 0) {
        counter++;
    }
}
if (counter > 4) {
    this.collision();
}
编辑2:所以我尝试了Patrick的UInt8ClampedArray创意:

//8 sensors for collision testing, positioned evenly around the brush point
    var detectionRadius = this.width / 2 + 1;
    var counter = 0;
    for (var i = 0; i < 16; i += 2) {
        var x = this.x + collisionPixels[i] * detectionRadius;
        var y = this.y + collisionPixels[i + 1] * detectionRadius;
        //translate into UInt8ClampedArray for data
        var index = (y * canvas.width + x) * 4 + 3; //+3 so we're at the alpha index
        if (canvasArray[index] != 0) {
            counter++;
        }
    }
希望我做得对。这是可行的,但是每玩一轮,内存和帧率都会变得更差。将上载一些堆快照

编辑3:

快照1:

快照2:

快照1位于第一局之后,快照2位于第二局之后

编辑4:尝试限制帧速率:

function loop() {
    requestAnimationFrame(loop);

    now = Date.now();
    delta = now - lastUpdate;
    //lastUpdate = now;

    if (delta > interval) {
        lastUpdate = now;
        if (!paused) {
            for (var i = 0; i < numPlayers; i++) {
                if (players[i].alive) {
                    players[i].update(delta);
                    players[i].render();
                }
            }
        }
    }
}
它延迟了最终的性能影响,但使用此选项时内存仍在增加

编辑5:虽然我确信一定有更好的方法,但我找到了一个相当有效的解决方案。将帧速率限制在30左右实际上在长期性能方面是有效的,但我讨厌游戏以每秒30帧的速度运行。。所以我构建了一个循环,除了冲突处理(我以30 FPS的速度更新)之外,所有更新和渲染都有一个无上限的帧速率

function loop() {
    requestAnimationFrame(loop);

    now = Date.now();
    delta = now - lastUpdate;
    lastUpdate = now;

    if (!paused) {
        for (var i = 0; i < numPlayers; i++) {
            if (players[i].alive) {
                players[i].update(delta);
                players[i].render();
            }
        }
        if (now - lastCollisionUpdate > collisionInterval) {
            canvasData = context.getImageData(0, 0, context.canvas.width, context.canvas.height).data;
            for (var i = 0; i < numPlayers; i++) {
                if (players[i].alive) {
                    if (players[i].detectCollisions()) {
                        players[i].collision();
                    }
                }
            }
            lastCollisionUpdate = now;
        }
        canvasData = null;
    }
}
//separate update cycle for collision detection
var collisionFPS = 30;
var lastCollisionUpdate;
var collisionInterval = 1000 / collisionFPS;
var canvasData;

function loop() {
    requestAnimationFrame(loop);

    now = Date.now();
    delta = now - lastUpdate;
    lastUpdate = now;

    if (!paused) {
        for (var i = 0; i < numPlayers; i++) {
            if (players[i].alive) {
                players[i].update(delta);
                players[i].render();
            }
        }
        if (now - lastCollisionUpdate > collisionInterval) {
            canvasData = context.getImageData(0, 0, context.canvas.width, context.canvas.height).data;
            for (var i = 0; i < numPlayers; i++) {
                if (players[i].alive) {
                    if (players[i].detectCollisions()) {
                        players[i].collision();
                    }
                }
            }
            lastCollisionUpdate = now;
        }
        canvasData = null;
    }
}
函数循环(){
请求动画帧(循环);
now=Date.now();
delta=now-lastUpdate;
lastUpdate=now;
如果(!暂停){
对于(变量i=0;icollisionInterval){
canvasData=context.getImageData(0,0,context.canvas.width,context.canvas.height);
对于(变量i=0;i

谢谢你的回答。。你的很多想法都融入到了最终的产品中,我对此表示感谢。关闭此线程。

是否存在可以调用
context.getImageData(0,0,context.canvas.width,context.canvas.height).data
的点,以便您可以使用单个
uint8clampedaray
而不是使用多个?另外,当您处理完图像数据(即图像数据中的
ImageData
,而不是
TypedArray
)后,您可以尝试调用图像数据中的
delete
,尽管我不确定这是否会释放内存。

虽然我肯定肯定有更好的方法,但我找到了一个相当好的解决方案。将帧速率限制在30左右实际上在长期性能方面是有效的,但我讨厌游戏以每秒30帧的速度运行。。所以我构建了一个循环,除了冲突处理(我以30 FPS的速度更新)之外,所有更新和渲染都有一个无上限的帧速率

function loop() {
    requestAnimationFrame(loop);

    now = Date.now();
    delta = now - lastUpdate;
    lastUpdate = now;

    if (!paused) {
        for (var i = 0; i < numPlayers; i++) {
            if (players[i].alive) {
                players[i].update(delta);
                players[i].render();
            }
        }
        if (now - lastCollisionUpdate > collisionInterval) {
            canvasData = context.getImageData(0, 0, context.canvas.width, context.canvas.height).data;
            for (var i = 0; i < numPlayers; i++) {
                if (players[i].alive) {
                    if (players[i].detectCollisions()) {
                        players[i].collision();
                    }
                }
            }
            lastCollisionUpdate = now;
        }
        canvasData = null;
    }
}
//separate update cycle for collision detection
var collisionFPS = 30;
var lastCollisionUpdate;
var collisionInterval = 1000 / collisionFPS;
var canvasData;

function loop() {
    requestAnimationFrame(loop);

    now = Date.now();
    delta = now - lastUpdate;
    lastUpdate = now;

    if (!paused) {
        for (var i = 0; i < numPlayers; i++) {
            if (players[i].alive) {
                players[i].update(delta);
                players[i].render();
            }
        }
        if (now - lastCollisionUpdate > collisionInterval) {
            canvasData = context.getImageData(0, 0, context.canvas.width, context.canvas.height).data;
            for (var i = 0; i < numPlayers; i++) {
                if (players[i].alive) {
                    if (players[i].detectCollisions()) {
                        players[i].collision();
                    }
                }
            }
            lastCollisionUpdate = now;
        }
        canvasData = null;
    }
}
//冲突检测的单独更新周期
var碰撞fps=30;
var lastCollisionUpdate;
var碰撞间隔=1000/碰撞每秒;
var数据;
函数循环(){
请求动画帧(循环);
now=Date.now();
delta=now-lastUpdate;
lastUpdate=now;
如果(!暂停){
对于(变量i=0;icollisionInterval){
canvasData=context.getImageData(0,0,context.canvas.width,context.canvas.height);
对于(变量i=0;i

可能不是最好的解决方案,但它是一致的。

什么是“skyrockets”,或多或少?你能提供一个可以运行的例子来说明这个问题吗?我在这段代码中没有看到内存泄漏的任何原因,但是代码效率不高,所以我怀疑问题更多的是你的游戏在时间上非常紧张,没有给GC留下多少时间。您能否向我们展示如何调用循环(例如,您是否使用setTimeout/Interval、requestAnimationFrame…)@KenFyrstenberg编辑到描述中;它是requestAnimationFrame()。今晚晚些时候我将尝试使用帧率上限,看看这是否给GC时间。这本身并不能解决您的问题,但您正在不必要地重新说明一些变量。我会在循环外定义x、y和索引。我尝试运行delete,但它不会释放内存。但是第一个想法听起来很有希望:对UInt8ClampedArray不太熟悉,所以我会给你回复。@JackBritton你的
pixelData
是一个
UInt8ClampedArray
,只是为了澄清一下。
//separate update cycle for collision detection
var collisionFPS = 30;
var lastCollisionUpdate;
var collisionInterval = 1000 / collisionFPS;
var canvasData;

function loop() {
    requestAnimationFrame(loop);

    now = Date.now();
    delta = now - lastUpdate;
    lastUpdate = now;

    if (!paused) {
        for (var i = 0; i < numPlayers; i++) {
            if (players[i].alive) {
                players[i].update(delta);
                players[i].render();
            }
        }
        if (now - lastCollisionUpdate > collisionInterval) {
            canvasData = context.getImageData(0, 0, context.canvas.width, context.canvas.height).data;
            for (var i = 0; i < numPlayers; i++) {
                if (players[i].alive) {
                    if (players[i].detectCollisions()) {
                        players[i].collision();
                    }
                }
            }
            lastCollisionUpdate = now;
        }
        canvasData = null;
    }
}