簡體   English   中英

getImageData內存泄漏?

[英]getImageData memory leak?

背景:在過去的一周里,我一直在使用Canvas和JavaScript開發一款基本上是多向Tron的游戲。 我選擇不在每一幀都清除畫布,以便我的小線段留下痕跡。 對於碰撞檢測,我使用此功能:

// 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();
}

這里的目的是獲得刷點表面周圍8個像素的alpha值; alpha值為0僅在背景上。 如果總數為8的碰撞像素數大於4(這包括播放器后面的跟蹤),那么我調用collision()方法。 這個函數實際上運行得很好(這個IS在函數內部,因此這些聲明是本地的)。

問題是context.getImageData()我的內存使用量大幅增加,並且在3或4場比賽之后達到了幀速率。 只需剪切該行並為pixelData分配一些其他值,即使在進行其他計算時,所有內容都可以非常流暢地運行。

如何修復此內存泄漏? 並且,如果這種類型的碰撞檢測方法不那么復雜,那么它是什么?

編輯:根據要求,這是我的循環:

function 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();
            }
        }
    }
    requestAnimationFrame(loop);
}

編輯2:所以我嘗試了Patrick的UInt8ClampedArrays想法:

//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++;
        }
    }

並且,在我的循環頂部,我添加了一個新的全局變量,每幀更新一次:

var canvasArray = context.getImageData(0,0,canvas.width,canvas.height).data;

希望我做對了。 它有效,但你玩的每一輪的記憶和幀率都會變差。 要上傳一些堆快照。

編輯3:

快照1: https//drive.google.com/open?id = 0B8p3yyYzRjeY2pEa2Z5QlgxRUk&autuser = 0

快照2: https//drive.google.com/open?id = 0B8p3yyYzRjeV2pJb1NyazY3OWc&authuser = 0

快照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();
                }
            }
        }
    }
}

哪里

interval = 1000 / fps;

它延遲了最終的性能損失,但內存仍然在使用此選項。

編輯5:雖然我確信必須有更好的方法,但我找到了一個合理的解決方案。 將幀率限制在30左右實際上在長期性能方面有效,但我討厭游戲看30 FPS的方式..所以我構建了一個循環,它具有一個無上限的幀速率,用於所有更新和渲染除了碰撞處理,我以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;
    }
}

感謝您的回答..您的許多想法都進入了最終(?)產品,我對此表示贊賞。 關閉這個帖子。

您是否可以調用context.getImageData(0, 0, context.canvas.width, context.canvas.height).data以便您可以使用單個UInt8ClampedArray而不是您使用的多個? 此外,當您完成圖像數據( ImageData ,而不是其中的TypedArray )時,您可以嘗試在其上調用delete ,但我不確定是否會釋放內存。

雖然我確信必須有更好的方法,但我發現一個合理的解決方案。 將幀率限制在30左右實際上在長期性能方面有效,但我討厭游戲看30 FPS的方式..所以我構建了一個循環,它具有一個無上限的幀速率,用於所有更新和渲染除了碰撞處理,我以30 FPS更新。

//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;
    }
}

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM