Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chrome: out of memory due to web worker. Chrome not kicking off GC #11

Open
ch08532 opened this issue Sep 22, 2021 · 0 comments
Open

Chrome: out of memory due to web worker. Chrome not kicking off GC #11

ch08532 opened this issue Sep 22, 2021 · 0 comments

Comments

@ch08532
Copy link

ch08532 commented Sep 22, 2021

cross posted on JodusNodus/react-qr-reader just in case

Not sure if anybody is seeing this issue but I'll raise it here.

We've been using this component in one of our departmental COVID contact tracing apps. We built a very simple web app that runs hours on end scanning qr codes and configured on an android tablet. As part of this app, the react-qr-code component runs scans at 2hz (delay = 500 ms).

Recently, we have done a tablet update and noticed our app now will occasionally run out of memory. We have also confirmed this on Chrome (latest build on Win10). After hours of digging I have traced it down to the web worker with the allocation of the jsQR object. The Chrome version that worked without issue is version 85.0.4183. So from that version to now the gc algo must have changed.

Now, when I start up Chrome dev tools and manually perform a gc then memory is returned and all is normal.

We have also pulled the forked this version of the react-qr-reader (modern-react-qr-reader) and the problem exists there as well.

The only fix (hack?) that worked for us is to periodically bounce the web worker which forces the gc call.

example in the scan function (I modified the lib/index.js in the node_modules folder directly):

 let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
         
        // Recreate web worker
        if (!this.worker) {
          this.worker = new Worker(URL.createObjectURL(workerBlob));
          this.worker.onmessage = this.handleWorkerMessage;
        }
        //post
​       this.worker.postMessage(imageData);

and updated the handleWorkerMessage function to terminate the worker on every 50th scan interval:

if (!legacyMode && typeof delay == 'number' && this.worker) {

        //chrome gc not firing so this is the hack to force gc to run
        if (count % 50 === 0) {
        this.worker.terminate();
        this.worker = undefined;
        count = 0;
        }
        count++;
        this.timeout = setTimeout(this.check, delay);
      }

I've also looked at the demo site and if you watch the task manager the memory does in fact grow but it appears the gc kicks in a bit more reliably.

Also, we changed the web worker postMessage call to use a transferrable object but that too did not solve the problem.

ex:

   let r = new ArrayBuffer(8);
   r = imageData.data.buffer
   this.worker.postMessage(r, [ r ]);

and in the webworker changed:

var e=jsQR(new Uint8ClampedArray(o.data),600,600); //hardcoded width and height for testing

Overall, the problem really only manifests if running for over 1/2 hr or so..sometimes longer sometimes shorter...all dependent on when the gc kicks off.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant