Total Canvas Memory Use Exceeds The Maximum Limit

You’re using the HTML Canvas Element in your new web app and decide to quickly test on iOS Safari. Suddenly your canvas isn’t drawn and the console shows a yellow warning “Total canvas memory use exceeds the maximum limit”. What gives?

While you were busy building, Safari was busy stuffing itself.

Safari has a thing for hoarding <canvas> elements. When you’re done with a canvas, Safari will hold on to it for a while, even if you’re not referencing it.

It has a cute little showcase where it presents all the canvas elements it’s currently holding on to.

A grid layout showing canvas contents previews, canvas sizes, and the memory size of each canvas

That’s. Just. Great.

Safari on iOS has the same hobby. It desperatly wants to keep up with its big brother on MacOs but it just doesn’t have the same storage capacity.

Once the storage box is full, it’ll throw this message and start drawing transparent canvas elements.

Total canvas memory use exceeds the maximum limit

So how do we deal with this?

We’re going to have to help out Safari to clean up its mess. Get rid of the things it can’t or won’t throw away.

When we’re done with a <canvas> element we have to manually “release” it.

Meaning we resize the canvas to a very small size and clear its contents, this tricks Safari in to replacing the canvas in its storage with our compressed version.

The following function will do just that.

function releaseCanvas(canvas) {
    canvas.width = 1;
    canvas.height = 1;
    const ctx = canvas.getContext('2d');
    ctx && ctx.clearRect(0, 0, 1, 1);
}

Safari will still hold on to the <canvas> for a while, but at least now it won’t blow the roof of its storage depot.

Unfortunately the memory limit on iOS Safari is rather low. It’s limited to 384MB on version 15, it’s lower on earlier versions, and it’s probably device specific as well.

A canvas pixel is made up of 4 values, red, green, blue, and an alpha value. Combining this with the canvas size we can calculate the amount of memory a canvas requires.

4096 × 4096 × 4 = 67108864 Bytes = 64 Megabytes

This is also the max size of a canvas on Safari

Let’s exceed the 384MB limit by creating 8 of these canvas elements.

for (let i = 0; i < 8; i++) {
    const canvas = document.createElement('canvas');
    canvas.width = 4096;
    canvas.height = 4096;
    const ctx = canvas.getContext('2d');
    ctx && ctx.fillRect(0, 0, 100, 100);
}

If the maximum limit was exceeded earlier the getContext('2d') method will return null so that’s why we check if the ctx variable is set before calling fillRect

When we add the releaseCanvas function we force Safari to free up some memory and the warning goes away.

for (let i = 0; i < 8; i++) {
    const canvas = document.createElement('canvas');
    canvas.width = 4096;
    canvas.height = 4096;
    const ctx = canvas.getContext('2d');
    ctx && ctx.fillRect(0, 0, 100, 100);

    // Force release each canvas
    releaseCanvas(canvas);
}

What we should keep in mind is that Safari either:

So a page refresh might not clean up the error immediately, it might still show and only dissapear after multiple refreshes or clearing the cache.

I share web dev tips on Twitter, if you found this interesting and want to learn more, follow me there

More articles More articles