<div dir="ltr"><div>Hi Adam,</div><div><br></div><div>You are welcome! I am happy to say that your patch also fixes the memory leak. I believe there is another memory leak in the JavaScript runtime (see the end of the previous message). I am gonna look into it.</div><div><br></div><div>Sincerely,</div><div>Saulo</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Aug 24, 2016 at 1:17 PM, Adam Chlipala <span dir="ltr"><<a href="mailto:adamc@csail.mit.edu" target="_blank">adamc@csail.mit.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div 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><div><div class="h5">
<br>
<div>On 08/12/2016 09:55 PM, Saulo Araujo
wrote:<br>
</div>
</div></div><blockquote type="cite"><div><div class="h5">
<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 href="http://timesheet-ur.sauloaraujo.com:8080/TimeSheet/application" target="_blank">http://timesheet-ur.<wbr>sauloaraujo.com:8080/<wbr>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 href="https://snag.gy/2nF9fz.jpg" target="_blank">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 href="https://snag.gy/Crc3Vg.jpg" target="_blank">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 href="https://snag.gy/P5BLhq.jpg" target="_blank">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("<wbr>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("<wbr>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("<wbr>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(<wbr>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 href="https://github.com/saulo2/urweb/commit/dcd280c85595ceee60a4fb78a3bfaf413a9eb7b8#diff-867e8dfbbc36419eefc0dfdf9db32883" target="_blank">https://github.com/saulo2/<wbr>urweb/commit/<wbr>dcd280c85595ceee60a4fb78a3bfaf<wbr>413a9eb7b8#diff-<wbr>867e8dfbbc36419eefc0dfdf9db328<wbr>83</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 href="https://snag.gy/NicJow.jpg" target="_blank">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 href="https://snag.gy/nuVfhg.jpg" target="_blank">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 href="https://snag.gy/aPeUuK.jpg" target="_blank">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></fieldset>
<br>
</div></div><pre>______________________________<wbr>_________________
Ur mailing list
<a href="mailto:Ur@impredicative.com" target="_blank">Ur@impredicative.com</a>
<a href="http://www.impredicative.com/cgi-bin/mailman/listinfo/ur" target="_blank">http://www.impredicative.com/<wbr>cgi-bin/mailman/listinfo/ur</a>
</pre>
</blockquote>
<br>
</div>
<br>______________________________<wbr>_________________<br>
Ur mailing list<br>
<a href="mailto:Ur@impredicative.com">Ur@impredicative.com</a><br>
<a href="http://www.impredicative.com/cgi-bin/mailman/listinfo/ur" rel="noreferrer" target="_blank">http://www.impredicative.com/<wbr>cgi-bin/mailman/listinfo/ur</a><br>
<br></blockquote></div><br></div>