Total canvas memory use exceeds the maximum limit (Safari 12)

后端 未结 8 1487
栀梦
栀梦 2020-12-05 10:21

We are working on a visualization web application which use d3-force to draw a network on a canvas.

But now we’ve got a problem with browsers on iOS, where the proces

相关标签:
8条回答
  • 2020-12-05 10:21

    Probably this recent change in WebKit should be causing these issues https://github.com/WebKit/webkit/commit/5d5b478917c685e50d1032ccf761ca53fc8f1b74#diff-b411cd4839e4bbc17b00570536abfa8f

    0 讨论(0)
  • 2020-12-05 10:21

    Just wanted to say we have a web application using Three.js crashing on iPad Pro (1st gen) on iOS 12. Upgrading to iOS 13 Public Beta 7 fixed the issue. The application isn't crashing anymore.

    0 讨论(0)
  • 2020-12-05 10:26

    I had this problem for a long time, but it seems I was able to fix it today. I used a canvas and drawn on it several times without having a problem. However, sometimes after some resizing I got the exception "Total canvas memory usage exceeds the maximum limit", and my canvas seemed to have disappeared...

    My solution was to reduce the size of the canvas to 0 and then delete the entire canvas. Afterwards initialize a new canvas after the resize happened.

    DoResize();
    
    if (typeof canvas === "object" && canvas !== null) {
        canvas.width = 0;
        canvas.height = 0;
    
        canvas.remove();
        delete canvas;
        canvas = null;
    }
    
    canvas = document.createElement("canvas");              
    container.appendChild(canvas);
    
    // Just in case, wait for the Browser
    window.requestAnimationFrame(() => {
        let context = canvas.getContext("2d");
        context.moveTo(10, 10);
        context.lineTo(30, 30);
        context.stroke();
    });
    

    The requestAnimationFrame was not necessarily needed but I just wanted to wait for the Device to update the canvas. I tested that with an iPhone XS Max.

    0 讨论(0)
  • 2020-12-05 10:30

    Another data-point: I've found that the Safari Web Inspector (12.1 - 14607.1.40.1.4) holds on to every Canvas object created while it is open, even if they would otherwise be garbage-collected. Close the web-inspector and re-open it and most of the old canvases go away.

    This doesn't solve the original problem - exceeding canvas memory when NOT running web-inspector, but without knowing this little tid-bit, I wasted a bunch of time going down the wrong path thinking I wasn't releasing any of my temporary canvases.

    0 讨论(0)
  • 2020-12-05 10:32

    Someone posted an answer, that showed a workaround for this. The idea is to set height and width to 0 before deleting the canvases. It is not really a proper solution, but it will work in my cache system.

    I add a small example that creates canvases until an exception is thrown, then empties the cache and continues.

    Thank to the now anonymous person who posted this answer.

    let counter = 0
    
    // create a 1MB image
    const createImage = () => {
        const size = 512
    
        const canvas = document.createElement('canvas')
        canvas.height = size
        canvas.width = size
    
        const ctx = canvas.getContext('2d')
        ctx.strokeRect(0, 0, size, size)
        return canvas
    }
    
    const createImages = nbImage => {
        // create i * 1MB images
        const canvases = []
    
        for (let i = 0; i < nbImage; i++) {
            canvases.push(createImage())
        }
    
        console.log(`done for ${canvases.length} MB`)
        return canvases
    }
    
    const deleteCanvases = canvases => {
        canvases.forEach((canvas, i, a) => {
            canvas.height = 0
            canvas.width = 0
        })
    }
    
    let canvases = []
    const process = (frequency, size) => {
        setInterval(() => {
            try {
                canvases.push(...createImages(size))
                counter += size
                console.log(`total ${counter}`)
            }
            catch (e) {
                deleteCanvases(canvases)
                canvases = []
            }
        }, frequency)
    }
    
    
    process(2000, 1000)
    
    0 讨论(0)
  • 2020-12-05 10:43

    I've submitted a new bug report to Apple, no reply yet. I added the ability to execute the code shown below after I drew a line using Polylines in google maps:

    function makeItSo(){
      var foo = document.getElementsByTagName("canvas");
      console.log(foo);
      for(var i=0;i < foo.length;i++){
        foo[i].width = 32;
        foo[i].height = 32;
      }
    }
    

    Looking at the console output, only 4 canvas elements were found. But looking at the "canvas" panel in the Safari debugger, there were 33 canvases displayed (amount depends on the size of the web page you have open).
    After the above code runs, the canvases display shows the 4 canvasses that were found at a smaller size, as one might expect. All the other "orphaned" canvases are still displayed in the debugger.
    I suspect this confirms the "memory leak" theory- canvases that exists but are not in the document. When the amount of canvas memory you have is exceeded, nothing more can be rendered using canvases.
    Again, all this worked until IOS12. My older iPad running IOS 10 still works.

    0 讨论(0)
提交回复
热议问题