Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak with Web Worker / Canvas

Fiddle: https://jsfiddle.net/eimmot/065wxa9o/9/

Using Chrome, launch Task Manager (Shift+ESC), click the worker invert button a few times, each time it goes up ~10 MB. Anytime I receive a message back from the worker the memory goes up, it's not from modifying or accessing the canvas, it happens when the worker sends the message back to the main thread. It gets worse the larger the message is.

Adding the ImageData buffer to the optional transferables list on postMessage doesn't make a difference, same result, I'm wondering if there's another way I should approach this.

  imageData = ctx.getImageData(0, 0, 800, 600);
  worker.postMessage(imageData, [imageData.data.buffer]);

Still doesn't matter if the main thread and/or worker thread is transferring ownership. I can see in the console that the imageData object actually transfers ownership, but the memory still increases! I've tried memory profiling with chrome dev tools but I can't see where the increase is at.

Forcing GC in dev tools clears the memory. Sometimes GC runs automatically, sometimes it doesn't, when it does, it only releases like 10% of what's been allocated.

I've read a lot of pages last night but they all say the same thing and I feel like I am overlooking something simple.

Transferable objects: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)

Update

Chrome Version 48.0.2564.116 beta-m (64-bit)

Fiddle: https://jsfiddle.net/eimmot/065wxa9o/13/

Added a loop option, seems like the only way to release the memory is to terminate the thread, I wanted to avoid creating new threads each time though and just keep one open because there is a noticeable delay when creating a new one each time

like image 755
tomm1e Avatar asked Oct 19 '22 14:10

tomm1e


2 Answers

I've found a solution that works for me in Chrome. I made two major modifications to the looping version of your fiddle:

  1. Add imageData.data.buffer to the transfer list when returning it from the worker
  2. pass around the typed array, imageData.data, instead of the entire imageData object

Here's the modified fiddle: https://jsfiddle.net/065wxa9o/14/

Note that just adding the buffer to the worker's transfer list doesn't work (https://jsfiddle.net/065wxa9o/15/) I have to transfer just the typed array.

Chrome Version 52.0.2743.116 (64-bit)

like image 188
TheNeuralBit Avatar answered Nov 02 '22 11:11

TheNeuralBit


You dont have a memory leak. This is just normal GC behaviour and there is not much you can do to stop the seemingly excessive memory use.

I had a play with your fiddle changing the code so that the worker.onmessage function immediately called startWork, effectively putting it in a loop, send the data, receive the inverted data set, put it on the canvas, then call startWork again and let it go while I had a coffee. It ran just fine.

Watching processes on chrome 49.0.2623.47 beta-m the memory useage peeked at about 110mb but never runs out of memory. Both Heap allocations and Timeline show normal behaviour and no leaks. Chrome has made some changes to GC so that it defers its actions in favour of the DOM and Javascript which may, if you are not used to it, look like memory usage has gone up, It is nothing to worry about. All that matters is that when you need memory it is available. GC will clean up if critical low memory, and it is better to have some dead memory rather than block the DOM or Javascript when they are busy, just to dump some unneeded memory.

like image 45
Blindman67 Avatar answered Nov 02 '22 11:11

Blindman67