Summmary
This is the first progress report on the project to identify the cause of, and suggest resolutions for, memory leaks in the Evergreen staff client associated with printing checkout receipts.
My findings to date are:
-
There is indeed a memory leak associated with the act of marking a checkout session "done".
-
However, the leak is not associated with the printing process per se.
-
At present, it appears that the leak is associated with the action of the command handler for the "Done" button calling xulG.set_tab to reload the current tab with a fresh checkout session.
-
A smaller leak is associated with using the "Other → Exit" submenu option to end the session.
-
The memory leak is not directly caused by xulG.set_tab itself. Using F1 to start a new checkout session (rather than using the "Done" button) does not result in a leak.
Methods
All testing took place on a test system installed with a recent master branch version of Evergreen. Staff client testing was done on a 64-bit Windows 7 PC.
AutoHotKey was used to drive the test client. The following AutoHotKey script was used to perform 15 iterations of bringing up the checkout page, entering a patron barcode, then clicking the "Done" button. Before each test run, the staff client was restarted, brought to the checkout page, and the cache cleared.
Memory consumption was measured using Windows Task Manager. For each test, the consumption was recorded just before the AutoHotKey script was run and 15-30 seconds after it had finished (to allow time for the XUL garbage collector to stabilize memory consumption).
#z:: Loop 15 { WinActivate 1: egadmin@BR1-delong.evergreen.metaquarry WinWaitActive 1: egadmin@BR1-delong.evergreen.metaquarry Sleep 1000 WinActivate 1: egadmin@BR1-delong.evergreen.metaquarry WinWaitActive 1: egadmin@BR1-delong.evergreen.metaquarry Send pat123{Enter} Sleep 5000 WinActivate 1: egadmin@BR1-delong.evergreen.metaquarry WinWaitActive 1: egadmin@BR1-delong.evergreen.metaquarry Send !d Sleep 5000 } MsgBox All done!
The following script, which is a variation of the first, uses F1 rather than the "Done" button to start a new checkout session.
#z:: Loop 15 { WinActivate 1: egadmin@BR1-delong.evergreen.metaquarry WinWaitActive 1: egadmin@BR1-delong.evergreen.metaquarry Sleep 1000 WinActivate 1: egadmin@BR1-delong.evergreen.metaquarry WinWaitActive 1: egadmin@BR1-delong.evergreen.metaquarry Send pat123{Enter} Sleep 5000 WinActivate 1: egadmin@BR1-delong.evergreen.metaquarry WinWaitActive 1: egadmin@BR1-delong.evergreen.metaquarry Send {F1} Sleep 5000 } MsgBox All done!
A third script, similar to the first two, was used that sends Alt-O followed by "x" to invoke the "Other → Exit" submenu item to refresh the checkout page.
Results
The following table records all of the variations tested to date. The unit for memory usage is kilobytes.
Test | Memory Use at Start | Memory Use at End | Comments |
---|---|---|---|
Using F1 to refresh checkout session |
66,288 |
86,940 |
|
Using "Done" to refresh checkout session |
62,336 |
307,052 |
This is evidence, not that this is unexpected, that the memory leak is real. Closing the main window does not result in the memory being reclaimed. |
Using "Other → Exit" to refresh the checkout session |
62,596 |
185,932 |
This also causes a leak, but less of one |
Using "Done", but with code to invoke printing commented out |
66,212 |
301,564 |
Conclusion is that the printing process (opening a temporary window with the receipt text and invoking the XUL print routines) does not itself significantly contribute to the memory leak |
Repeat of above test |
69,804 |
307,152 |
This indicates that there is some variability in the exact memory usage from run to run. The difference is what matters. |
As above, with several changes to attempt to make util.controller.cleanup() clear references to the control map more thoroughly |
66,916 |
301,824 |
Conclusion is that util.contoller per se is not hanging on to XUL nodes or JavaScript execution contexts |
Next steps
At present, my focus is two-fold. First, the patron display and checkout pages rank as among the most complex XUL structures that the staff client produces. When that gets torn down (either because the tab has been closed in the staff client or been directed to restart a checkout session, a number of cleanup routines are called. I will trace the various ways that the checkout page can be closed to verify that all of the cleanup routines get called, regardless of whether F1, Control-W, "Done", or "Other → Exit" are used to close or restart the checkout session.
I will also work on tracing the process of a button’s command handler invoking xulG.set_tab() to reload the active tab, as the "Done" and "Other → Exit" handlers do. It is possible that invoking set_tab() from a handler belonging to the page that is to be destroyed may be resulting references to XUL nodes and/or Javascript execution contexts not being fully removed. This situation is different from the case where set_tab() is invoked by a menu handler or global hotkey handler (e.g., "F1"), as in that case the handler itself is not meant to be pruned.