javascriptgoogle-chromememorymemory-leaksweb-mediarecorder

Why does Chrome retain an anonymous MediaRecorder object in memory?


After trying to understand why some of my Web application's objects were retained in memory by Chrome I think I may have narrowed it down to a case of a MediaRecorder object not being garbage collected even with the application having let go of all the references to it (whether explicit or "implicit").

A minimal example that reproduces the issue:

new MediaRecorder(new MediaStream())

After evaluating the above expression -- a MediaRecorder object being created with no references (variables or properties) to it being assigned, I profiled the heap usage using the Memory tab in both Chrome, Electron and Chromium -- the object remains on the heap for as long as I cared to find it there. It doesn't disappear.

Why is it retained? Testing with a trivial class like Object instead -- evaluating new Object(), for example, behaves as expected -- garbage collection eventually collects the anonymous object. But not so with MediaRecorder. This smells an awful lot like a bug to me.

Firefox, by comparison, releases the MediaRecorder object in due time (it's garbage collected), it is certainly no longer on the heap mere seconds after I execute new MediaRecorder(new MediaStream()).

The media recorder object is obviously not referenced by anything in the application and should thus have the shortest lifetime an object may ever have, yet it is there in memory afterwards in the snapshot I take after the console is cleared (the developers behind Developer Tools for Chrome recommend clearing the console before taking a heap snapshot because the former may hold on to objects that otherwise would be released).

I can't find any methods in the MediaRecorder class that would indicate to me one can "disassociate" it from a stream or otherwise "close" it. Short of making sure there are no obvious or not-so-obvious (e.g. through event listeners) references to it, I can only hope that an anonymous object isn't retained, and such objects usually aren't, but MediaRecorder objects seem to be with Chromium. There doesn't seem to be any lever for me to pull to dispose of one, so to speak.

You can see in the screenshot below that what objects retain the media recorder aren't exactly part of my scripts, they rather seem to be related to some internal browser state:

Screenshot of Memory pane in the Chrome Developer Tools

The window icon next to the object selected in the "Constructor" column has the tooltip "User object [is] reachable from window". The snippet above is the only code I run in the tab, why would the object be "reachable from window", and if it is, it surely cannot be any references I manage?

So why is the object retained? The larger problem here is that if my application initiates many recordings and creates a new media recorder object for each, these objects will just keep piling up in memory, a de-facto case of memory leaking.

Like I said, I ran the same statement in Firefox 62.0.2 and there the behaviour is as I would expect -- the single MediaRecorder object I created seems to go out of scope (as it should being how it should have no references to it) shortly after it is created.

(Chrome version 69.0.3497.100, x64 on Windows 10)


Solution

  • This was confirmed to be an issue with Chromium (and by implication Google Chrome and probably other Chromium derivatives, including Electron):

    https://bugs.chromium.org/p/chromium/issues/detail?id=899722

    At the time of writing this the issue is flagged as "available", which I presume communicates that it's acknowledged and effectively waiting for someone to step in and fix.