[Ur] Substantial memory leak in the JavaScript runtime
Adam Chlipala
adamc at csail.mit.edu
Wed Aug 24 12:17:00 EDT 2016
Thanks for spotting this problem. I've pushed a different fix that
makes dynamic input elements create <script> tags, so that the original
dyn() code finds them to garbage-collect. Does this change also seem to
fix the problem?
(I'd like to avoid using createNodeIterator(), which only became widely
deployed about 5 years ago. I think Ur/Web client-side reactive code
today will still work on browsers from about the year 2000, and I'd like
to keep it that way unless there's a very compelling reason to the
contrary.)
On 08/12/2016 09:55 PM, Saulo Araujo wrote:
> Hi,
>
> I believe there is a substantial memory leak in the JavaScript runtime
> of Ur/Web. To see it happening:
>
> 1) visit
> http://timesheet-ur.sauloaraujo.com:8080/TimeSheet/application with
> Google Chrome
> 2) open the developer tools by pressing f12
> 3) click in the "Profiles" tab
> 4) click in the "Take Heap Snapshot" radio button
> 5) click in the "Take Snapshot" button
> 6) type Detached in the "Class filter" text box (you will see that the
> heap has about 7MB and Detached DOM trees are retaining 0% of the
> memory - https://snag.gy/2nF9fz.jpg)
>
> 7) click 10 times in the foward icon (the one on the right of the
> "Date" header in the time sheet application)
> 9) click in the "Take Snapshot" button
> 10) type Detached in the "Class filter" text box (you will see that
> the heap has about 43MB and Detached DOM trees are retaining 16% of
> the memory - https://snag.gy/Crc3Vg.jpg)
>
> 11) click 10 times in the foward icon (the one on the right of the
> "Date" header in the time sheet application)
> 12) click in the "Take Snapshot" button
> 13) type Detached in the "Class filter" text box (you will see that
> the heap has about 78MB and Detached DOM trees are retaining 17% of
> the memory - https://snag.gy/P5BLhq.jpg)
>
> I have spent quite some time investigating this memory leak and I
> believe the problem is in the function recreate inside the function dyn:
>
> function dyn(pnode, s) {
> if (suspendScripts)
> return;
>
> var x = document.createElement("script");
> x.dead = false;
> x.signal = s;
> x.sources = null;
> x.closures = null;
>
> var firstChild = null;
>
> x.recreate = function(v) {
> for (var ls = x.closures; ls; ls = ls.next)
> freeClosure(ls.data);
>
> var next;
> for (var child = firstChild; child && child != x; child = next) {
> next = child.nextSibling;
>
> killScript(child);
> if (child.getElementsByTagName) {
> var arr = child.getElementsByTagName("script");
> for (var i = 0; i < arr.length; ++i)
> killScript(arr[i]);
> }
> ...
>
> Note that recreate only kills <script> nodes . Therefore, <input>,
> <textarea> and <select> nodes created through <ctextbox>, <ctextarea>
> and <cselect> will continue to be in the dyns lists of its sources. To
> fix this memory leak, I propose changing the function dyn to
>
> function dyn(pnode, s) {
> if (suspendScripts)
> return;
>
> var x = document.createElement("script");
> x.dead = false;
> x.signal = s;
> x.sources = null;
> x.closures = null;
>
> var firstChild = null;
>
> x.recreate = function(v) {
> for (var ls = x.closures; ls; ls = ls.next)
> freeClosure(ls.data);
>
> var next;
> for (var child = firstChild; child && child != x; child = next) {
> next = child.nextSibling;
>
> killDyns(child)
> ...
>
> Below is the function killDyns.
>
> function killDyns(node) {
> var nodeIterator = document.createNodeIterator(node,
> NodeFilter.SHOW_ELEMENT, function (node) {
> return node.dead !== undefined && node.dead === false
> })
> var node = nodeIterator.nextNode();
> while (node) {
> killScript(node);
> node = nodeIterator.nextNode();
> }
> }
>
> killDyns traverses all descendants of a node that have a dead
> attribute equal to false and kills them with killScript. Therefore,
> killDyns may be less performant than the code it substitutes, but I
> believe killDyns is less prone to memory leaks than the original code.
> There is another small change to be done in urweb.js. You can see all
> changes in
> https://github.com/saulo2/urweb/commit/dcd280c85595ceee60a4fb78a3bfaf413a9eb7b8#diff-867e8dfbbc36419eefc0dfdf9db32883
>
> I did not make a pull request yet because I would like to know the
> opinion of the Ur/Web comitters about this fix. Maybe there is
> something that can be improved. Maybe there is a new bug in it :) In
> any case, repeating the previous steps with the proposed changes, I
> get the following results:
>
> 6) type Detached in the "Class filter" text box (you will see that the
> heap has about 7MB and Detached DOM trees are retaining 0% of the
> memory - https://snag.gy/NicJow.jpg)
> 10) type Detached in the "Class filter" text box (you will see that
> the heap has about 15MB and Detached DOM trees are retaining 0% of the
> memory - https://snag.gy/nuVfhg.jpg)
> 13) type Detached in the "Class filter" text box (you will see that
> the heap has about 21MB and Detached DOM trees are retaining 0% of the
> memory - https://snag.gy/aPeUuK.jpg)
>
> The new results suggest that there is another memory leak in the
> JavaScript Runtime. However, I have not looked into it yet.
>
> Sincerely,
> Saulo
>
>
> _______________________________________________
> Ur mailing list
> Ur at impredicative.com
> http://www.impredicative.com/cgi-bin/mailman/listinfo/ur
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.impredicative.com/pipermail/ur/attachments/20160824/648ff280/attachment.html>
More information about the Ur
mailing list