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.