Bug #12112
Memory leak in client JVM caused by deleted dynamic windows persisting
0%
Related issues
History
#2 Updated by Șerban Bursuc about 1 hour ago
- Related to Bug #10530: Move cursor change logic from JS client to the FWD client added
#3 Updated by Șerban Bursuc about 1 hour ago
This should affect all the customer projects that use UI and also create dynamic windows. It is not a regression and has been present for a while at the very least. Found during #10530 regression testing using cursor related testcases. Report below.
Symptom¶
A window created at runtime and then deleted (CREATE WINDOW, DELETE WIDGET) stays in the memory of the FWD client process, together with its frames, the widgets in them and their mouse actions. Nothing frees them later: every deleted window adds to the client heap, so a session that keeps opening and closing windows grows for as long as it runs. The windows do not have to be hovered or clicked, and no mouse pointer is involved; creating and deleting them is enough.
Per deleted window with one frame and three buttons, these stay live in the client JVM:
| Class | Instances per deleted window |
|---|---|
WindowGuiImpl |
1 |
FrameGuiImpl |
1 |
ButtonGuiImpl |
3 |
MouseHoverAction |
3 |
MouseEmptySelector |
1 |
Found while working on #10530. Same pattern as #10322.
Testcase¶
Each choose of the Cycle button creates and deletes 25 windows, each with a frame and three buttons:
/* Each choose of Cycle creates and deletes 25 windows, each with a frame and three buttons. */
DEFINE VARIABLE hWin AS HANDLE NO-UNDO.
DEFINE VARIABLE hFrm AS HANDLE NO-UNDO.
DEFINE VARIABLE hBtn AS HANDLE NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DEFINE BUTTON bCycle LABEL "Cycle".
DEFINE FRAME f bCycle.
ON CHOOSE OF bCycle
DO:
DO i = 1 TO 25:
CREATE WINDOW hWin
ASSIGN WIDTH = 40
HEIGHT = 10
VISIBLE = TRUE.
CREATE FRAME hFrm
ASSIGN PARENT = hWin
WIDTH = 38
HEIGHT = 8
VISIBLE = TRUE.
DO j = 1 TO 3:
CREATE BUTTON hBtn
ASSIGN FRAME = hFrm
ROW = j * 2
COLUMN = 3
LABEL = "B" + STRING(j)
SENSITIVE = TRUE
VISIBLE = TRUE.
END.
DELETE WIDGET hWin.
END.
END.
ENABLE bCycle WITH FRAME f.
WAIT-FOR WINDOW-CLOSE OF CURRENT-WINDOW.
Steps, FWD trunk rev 16818, web GUI client:
- Run the testcase and log in.
- Take the histogram below.
- Choose Cycle (25 windows created and deleted), take the histogram again.
- Choose Cycle again (50 windows), take the histogram again.
Measurement¶
Run jmap as the OS user the client JVM runs under. jmap -histo:live runs a full garbage collection first, so it counts only objects that are still reachable:
PID=$(pgrep -n -f '^java .*ClientDriver') jmap -histo:live $PID | grep -E '#instances|^---|[.](WindowGuiImpl|FrameGuiImpl|ButtonGuiImpl|MouseHoverAction|MouseEmptySelector)$'
After the login (the default window, its frame and the Cycle button):
num #instances #bytes class name (module) ------------------------------------------------------- 629: 1 448 com.goldencode.p2j.ui.client.gui.FrameGuiImpl 800: 1 264 com.goldencode.p2j.ui.client.gui.WindowGuiImpl 1011: 1 160 com.goldencode.p2j.ui.client.gui.ButtonGuiImpl 2011: 1 40 com.goldencode.p2j.ui.client.gui.driver.MouseEmptySelector 2013: 1 40 com.goldencode.p2j.ui.client.gui.driver.MouseHoverAction
After 25 windows created and deleted:
num #instances #bytes class name (module) ------------------------------------------------------- 126: 76 12160 com.goldencode.p2j.ui.client.gui.ButtonGuiImpl 131: 26 11648 com.goldencode.p2j.ui.client.gui.FrameGuiImpl 174: 26 6864 com.goldencode.p2j.ui.client.gui.WindowGuiImpl 265: 76 3040 com.goldencode.p2j.ui.client.gui.driver.MouseHoverAction 452: 26 1040 com.goldencode.p2j.ui.client.gui.driver.MouseEmptySelector
After 50 windows created and deleted:
num #instances #bytes class name (module) ------------------------------------------------------- 93: 151 24160 com.goldencode.p2j.ui.client.gui.ButtonGuiImpl 97: 51 22848 com.goldencode.p2j.ui.client.gui.FrameGuiImpl 127: 51 13464 com.goldencode.p2j.ui.client.gui.WindowGuiImpl 203: 151 6040 com.goldencode.p2j.ui.client.gui.driver.MouseHoverAction 331: 51 2040 com.goldencode.p2j.ui.client.gui.driver.MouseEmptySelector
Every deleted window remains: each 25 windows add 25 windows, frames and selectors and 75 buttons and hover actions. The histograms only list a few classes; everything these widgets reference stays as well.
Cause¶
Deleting the window calls destroy() for its own parts (title bar, caption buttons, status line, message area) but never for its frames and their widgets, so MouseHandler.deregisterWidget never runs for them. Their actions stay in the MouseHandler registry (WorkArea.actions): the buttons' MouseHoverAction (from AbstractWidget._setEnabled) and the frame's MouseEmptySelector (from AbstractGuiDriver.registerEmptySelector). Each action holds its widget (MouseWidgetAction.widget), which keeps the whole window reachable.
#4 Updated by Șerban Bursuc about 1 hour ago
- Assignee set to Șerban Bursuc
If this hasn't been fixed yet in a branch I can take a look at this.
#5 Updated by Constantin Asofiei 20 minutes ago
Serban, please confirm the test in 4GL - what does valid-handle say for the hFrm and hBtn widgets? Because to me it doesn't look like is FWD's responsibility to clean this up.
#6 Updated by Șerban Bursuc 1 minute ago
Constantin Asofiei wrote:
Serban, please confirm the test in 4GL - what does
valid-handlesay for thehFrmandhBtnwidgets? Because to me it doesn't look like is FWD's responsibility to clean this up.
Didn't consider the possibility of the 4GL being bad and you're right, 4GL does not delete the frame and its content either after deleting the window widget handle. This is an AI test generation issue, it should probably be put in a skill somewhere to do a proper cleanup.
There's still a difference though - when adding DELETE WIDGET hFrm to the testcase the client side memory is fixed but the server side seems to still grow. jmap shows 1 WindowWidget, 1 FrameWidget and 2 ButtonWidget widgets after each cycle. In OE all widgets become invalid when queried with VALID-HANDLE. I will draft the report once I double check the issue.