<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p>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?</p>
<p>(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.)<br>
</p>
<br>
<div class="moz-cite-prefix">On 08/12/2016 09:55 PM, Saulo Araujo
wrote:<br>
</div>
<blockquote
cite="mid:CA+ckhoTcGRN=uhb5a7Ed5J5BGRRZUHWT5_yV7+yonEjVu=unrg@mail.gmail.com"
type="cite">
<div dir="ltr">
<div>Hi,</div>
<div><br>
</div>
<div>I believe there is a substantial memory leak in the
JavaScript runtime of Ur/Web. To see it happening:</div>
<div><br>
</div>
<div>1) visit <a moz-do-not-send="true"
href="http://timesheet-ur.sauloaraujo.com:8080/TimeSheet/application">http://timesheet-ur.sauloaraujo.com:8080/TimeSheet/application</a>
with Google Chrome</div>
<div>2) open the developer tools by pressing f12</div>
<div>3) click in the "Profiles" tab</div>
<div>4) click in the "Take Heap Snapshot" radio button</div>
<div>5) click in the "Take Snapshot" button</div>
<div>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 - <a moz-do-not-send="true"
href="https://snag.gy/2nF9fz.jpg">https://snag.gy/2nF9fz.jpg</a>)</div>
<div><br>
</div>
<div>7) click 10 times in the foward icon (the one on the right
of the "Date" header in the time sheet application)</div>
<div>9) click in the "Take Snapshot" button</div>
<div>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 - <a moz-do-not-send="true"
href="https://snag.gy/Crc3Vg.jpg">https://snag.gy/Crc3Vg.jpg</a>)</div>
<div><br>
</div>
<div>11) click 10 times in the foward icon (the one on the right
of the "Date" header in the time sheet application)</div>
<div>12) click in the "Take Snapshot" button</div>
<div>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 - <a moz-do-not-send="true"
href="https://snag.gy/P5BLhq.jpg">https://snag.gy/P5BLhq.jpg</a>)</div>
<div><br>
</div>
<div>I have spent quite some time investigating this memory leak
and I believe the problem is in the function recreate inside
the function dyn:</div>
<div><br>
</div>
<div>function dyn(pnode, s) {</div>
<div> if (suspendScripts)</div>
<div> return;</div>
<div><br>
</div>
<div> var x = document.createElement("script");</div>
<div> x.dead = false;</div>
<div> x.signal = s;</div>
<div> x.sources = null;</div>
<div> x.closures = null;</div>
<div><br>
</div>
<div> var firstChild = null;</div>
<div><br>
</div>
<div> x.recreate = function(v) {</div>
<div> for (var ls = x.closures; ls; ls = ls.next)</div>
<div> freeClosure(ls.data);</div>
<div><br>
</div>
<div> var next;</div>
<div> for (var child = firstChild; child && child
!= x; child = next) {</div>
<div> next = child.nextSibling;</div>
<div><br>
</div>
<div> killScript(child);</div>
<div> if (child.getElementsByTagName) {</div>
<div> var arr =
child.getElementsByTagName("script");</div>
<div> for (var i = 0; i < arr.length; ++i)</div>
<div> killScript(arr[i]);</div>
<div> }</div>
<div>...</div>
<div><br>
</div>
<div>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</div>
<div><br>
</div>
<div>function dyn(pnode, s) {</div>
<div> if (suspendScripts)</div>
<div> return;</div>
<div><br>
</div>
<div> var x = document.createElement("script");</div>
<div> x.dead = false;</div>
<div> x.signal = s;</div>
<div> x.sources = null;</div>
<div> x.closures = null;</div>
<div><br>
</div>
<div> var firstChild = null;</div>
<div><br>
</div>
<div> x.recreate = function(v) {</div>
<div> for (var ls = x.closures; ls; ls = ls.next)</div>
<div> freeClosure(ls.data);</div>
<div><br>
</div>
<div> var next;</div>
<div> for (var child = firstChild; child && child
!= x; child = next) {</div>
<div> next = child.nextSibling;</div>
<div><br>
</div>
<div> killDyns(child)</div>
<div>...</div>
<div><br>
</div>
<div>Below is the function killDyns.</div>
<div><br>
</div>
<div>function killDyns(node) {</div>
<div> var nodeIterator = document.createNodeIterator(node,
NodeFilter.SHOW_ELEMENT, function (node) {</div>
<div> return node.dead !== undefined && node.dead
=== false</div>
<div> })</div>
<div> var node = nodeIterator.nextNode();</div>
<div> while (node) {</div>
<div> killScript(node);</div>
<div> node = nodeIterator.nextNode();</div>
<div> }</div>
<div>}</div>
<div><br>
</div>
<div>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 <a
moz-do-not-send="true"
href="https://github.com/saulo2/urweb/commit/dcd280c85595ceee60a4fb78a3bfaf413a9eb7b8#diff-867e8dfbbc36419eefc0dfdf9db32883">https://github.com/saulo2/urweb/commit/dcd280c85595ceee60a4fb78a3bfaf413a9eb7b8#diff-867e8dfbbc36419eefc0dfdf9db32883</a></div>
<div><br>
</div>
<div>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:</div>
<div><br>
</div>
<div>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 - <a moz-do-not-send="true"
href="https://snag.gy/NicJow.jpg">https://snag.gy/NicJow.jpg</a>)</div>
<div>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 - <a moz-do-not-send="true"
href="https://snag.gy/nuVfhg.jpg">https://snag.gy/nuVfhg.jpg</a>)</div>
<div>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 - <a moz-do-not-send="true"
href="https://snag.gy/aPeUuK.jpg">https://snag.gy/aPeUuK.jpg</a>)</div>
<div><br>
</div>
<div>The new results suggest that there is another memory leak
in the JavaScript Runtime. However, I have not looked into it
yet.</div>
<div><br>
</div>
<div>Sincerely,</div>
<div>Saulo</div>
</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<br>
<pre wrap="">_______________________________________________
Ur mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Ur@impredicative.com">Ur@impredicative.com</a>
<a class="moz-txt-link-freetext" href="http://www.impredicative.com/cgi-bin/mailman/listinfo/ur">http://www.impredicative.com/cgi-bin/mailman/listinfo/ur</a>
</pre>
</blockquote>
<br>
</body>
</html>