WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED INVALID
302801
Decoding multiple images simultaneously crashes the browser
https://bugs.webkit.org/show_bug.cgi?id=302801
Summary
Decoding multiple images simultaneously crashes the browser
Mouad Debbar
Reported
2025-11-19 10:21:46 PST
## Reproduction See this jsfiddle for repro:
https://jsfiddle.net/mdebbar/ndej2p01/23/
In the jsfiddle, `mainParallel` attempts to decode 20 images in parallel, and causes Safari iOS to crash. Switching to `mainSerial`, which decodes the images one by one, seems to work and causes no crashes. I can reproduce this on my iOS 26 device. Not sure about older versions, but I assume they have a similar behavior. ## Expected behavior If a web page inserts many `<img>` elements into the document, the browser doesn't crash. It seems to have some mechanism to decode the images in parallel but without crashing. Is there a way to use the same mechanism when calling `await img.decode()`? ## Use case In order to prevent a jumpy UI, some apps prefer to call `await img.decode()` on images before inserting them into the document. That way, the images are guaranteed to be ready to render immediately. This is also useful when using the `<img>` element as an Image source for drawing on a canvas.
Attachments
Add attachment
proposed patch, testcase, etc.
Alexey Proskuryakov
Comment 1
2025-11-19 13:52:04 PST
Than you for the report! I was able to reproduce with this jsfiddle, although it took several reloads. What I saw was technically not a crash, but the process being killed by the system because it used too much memory. Handling 20x 4000x4000 images is roughly where I'd expect this to happen, as the uncompressed images themselves add up to a gigabyte in size, plus everything else that the browser needs. Doing this in parallel may get the prices just above the limit due to intermediate data structures. Or it could also be that your sequential test doesn't hold to previous images, allowing for garbage collecting.
Mouad Debbar
Comment 2
2025-11-20 08:30:51 PST
@Alexey I think it depends on which phone is being used. I'm on a iPhone 15 Pro. The jsfiddle crashes every single time. A newer phone may have more memory and may crash less. I understand that this is memory-intensive and that's the reason for the crash. What I find puzzling is that the browser is able to handle the same number of images (and more) if I just dump them into the document. It somehow manages the memory in a way that allows it to decode all images and display them without crashing. Here's a better example showcasing the difference: If I insert the 20 images into the document as `<img>` elements, they work just fine. The browser is able to decode them and render them:
https://jsfiddle.net/mdebbar/1ghxnj80/10/
But if I want to wait until the image is ready before inserting it into the document, it causes the browser to crash:
https://jsfiddle.net/mdebbar/1ghxnj80/12/
Inserting the images directly into the document isn't ideal because it causes the UI to jump, and the image renders slowly from top to bottom. Using `await img.decode()` is the solution for this, and it works well on other browsers. Is there a solution that works well on iOS Safari?
Said Abou-Hallawa
Comment 3
2025-11-20 09:45:56 PST
Displaying the images is different from decoding them. We display the images only in the current viewport and maybe a little bit more outside the viewport to make scrolling smoother. So it is very hard to get 20 images each of size 4000x4000 to be displayed at the same updateRendering. Also when the image destination size is smaller than its natural size, we decode it with sub sampling. For example if an image of size 4000x4000 is displayed to a 100x100 element we may end up decoding it with size 400x400 or even 100x100. So sub-sampling is very useful technique in reducing the decoding memory. But when you call the method HTMLImageElement.decode(), decoding the images happens regardless whether they are shown in the viewport or not. Also the sub-sampling is disabled in this case. So all images have to be decoded with their natural sizes because we do not know their destination sizes. Maybe the specs need to add an optional decoding size to the decode() method. <img id="small-image" width="100" height="100"> <script> const img = new Image(); img.src = "4000x4000.jpg"; img.decode(100, 100).then(() => { document.querySelector("#small-image").src = img.src; }) <script>
Said Abou-Hallawa
Comment 4
2025-11-20 10:42:44 PST
I filed this issue
https://github.com/whatwg/html/issues/11935
Yegor
Comment 5
2025-11-20 19:56:01 PST
I think the whatwg feature request makes sense (although I have comments, which I'll leave there). That said, it also makes sense to fix this issue separately from introducing the extra decoding parameters. This is because the amount of available memory is opaque on the JavaScript side, and it's not hard to imagine some operating systems and/or browsers altering the available memory dynamically based on the overall system load, e.g. as part of some graceful degradation of functionality under load (slow things down rather than crash). This means that even with the additional parameters, there's still risk of hitting OOM. So it's impractical for web developers to predict which browser/OS/hardware combination may crash (which is how this bug was discovered). While not perfect, a better approach would be for WebKit to postpone the decoding promises. If the app reaches some internal memory limit, simply delay further decoding until more memory is available. This slows down image decoding but the page doesn't crash, and the JavaScript side has opportunities to recover. For example, if the img is on its way to become a WebGL texture, that texture can be sub-sampled, then the img element would be discarded freeing the memory. Even better, setting src to "" could signal to the browser that the underlying image resources can be collected immediately, without waiting for a GC cycle. The same recovery can be implemented for images destined for 2D canvas, or cloned and appended to the DOM.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug