JDK-8093738 : [SwingNode] Calling setContent method repeatedly produces memory leak
  • Type: Bug
  • Component: javafx
  • Sub-Component: swing
  • Affected Version: 8u5
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • Submitted: 2014-07-24
  • Updated: 2021-03-01
  • Resolved: 2014-08-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8u40Resolved
Related Reports
Relates :  
Description
public class SwingFx extends Application {

    @Override
    public void start(Stage stage) {
        final SwingNode swingNode = new SwingNode();
        createAndSetSwingContent(swingNode);

        Button bt = new Button("Add New");
        bt.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                swingNode.setContent(null);
                swingNode.setContent(new TestComp());
            }
        });
        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(swingNode);
        borderPane.setTop(bt);

        stage.setScene(new Scene(borderPane, 200, 150));
        stage.show();
    }

    private void createAndSetSwingContent(final SwingNode swingNode) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JButton bt = new JButton("Click me!");
                bt.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        System.out.println("Click me...");
                    }
                });
                swingNode.setContent(bt);
            }
        });
    }

    public static void main(String[] args) {
        launch(args);
    }


    class TestComp extends JComponent {
        private String[] strArr;

        TestComp() {
            this.strArr = new String[1000];
            for (int i = 0; i < 1000; i++) {
                strArr[i] = Math.random() + "";
            }
        }
    }
}


if we click the "Add New" button which will  set content to null at first ,and then add a class with array.
we using Eclispe Memory Analysis tool to analysis the heapdump,and find that the variable lwFrame with type JLightweightFrame increase, and force gc cannot release the memory:
���sun.swing.JLightweightFrame @ 0x921b8e0 - 278,288 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x911bc10 - 278,272 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x915fa88 - 278,208 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8c64068 - 278,200 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x921bd80 - 278,200 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x921d298 - 278,184 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x921c958 - 278,176 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8c642b8 - 278,168 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8d3cef8 - 278,168 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8c63e18 - 278,160 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x91e3af8 - 278,160 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8a20c58 - 278,144 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8c63b80 - 278,144 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8d3d920 - 278,144 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8d3dae8 - 278,144 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x921c220 - 278,144 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x921bb30 - 278,136 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8c63930 - 278,120 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8a207b8 - 278,112 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8a20a08 - 278,112 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x921d738 - 278,104 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x882b810 - 278,096 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x8c649a8 - 278,080 (1.56%) bytes. 
���sun.swing.JLightweightFrame @ 0x921cba8 - 278,080 (1.56%) bytes. 
 

how can we reset the SwingNode content rightly?
Comments
Thanks for confirming this.
08-09-2014

It's ok when using jdk ���build 1.8.0_40-ea-b02���
01-09-2014

FYI: The bug is only reproducible with 8u20b26 and older builds. I'm unable to reproduce it with 8u40b01 promoted build. So I've just closed the JDK bug. Once 8u40 ea builds start publishing at http://jdk8.java.net/download.html (should take a few weeks I suppose), please re-test and confirm that the bug is no longer there. If it's still reproducible for you, we'll continue investigating.
15-08-2014

FYI: JDK 9 is not affected. I've updated the JDK bug accordingly and targeted it for 8u40.
14-08-2014

I've filed a JDK bug to continue to work on this issue: https://bugs.openjdk.java.net/browse/JDK-8055066 This JavaFX bug report will be closed as Not an Issue because there's no bugs in the JavaFX code itself.
13-08-2014

It looks like TranslucentWindowPainter instances in WLightweightFramePeer implementation do not get disposed properly, which causes a loop in JNI global references that prevents JLF instances from being released.
13-08-2014

This seems to be a bug in JDK though. I can reproduce the same problem using the following (very ugly) awt-only test: import java.awt.*; import javax.swing.*; import sun.swing.*; import sun.awt.*; import java.awt.dnd.*; public class awt { public static void main(String[] args) throws Exception { for (int i = 0; i < 20; i++) { Frame f[] = new Frame[1]; EventQueue.invokeAndWait(() -> { //f[0] = new JFrame("test"); f[0] = new JLightweightFrame(); JComponent comp = new JComponent() {}; comp.setSize(300, 300); ((JLightweightFrame)f[0]).setContent(new LightweightContent() { public JComponent getComponent() { return comp; } public void paintLock() {} public void paintUnlock() {} public void imageBufferReset(int[] data, int x, int y, int width, int height, int linestride, int scale) { } public void imageBufferReset(int[] data, int x, int y, int width, int height, int linestride) { } public void imageReshaped(int x, int y, int width, int height) {} public void imageUpdated(int dirtyX, int dirtyY, int dirtyWidth, int dirtyHeight){} public void focusGrabbed(){} public void focusUngrabbed(){} public void preferredSizeChanged(int width, int height){} public void maximumSizeChanged(int width, int height){} public void minimumSizeChanged(int width, int height){} }); f[0].setSize(500, 500); f[0].setUndecorated(true); f[0].setBackground(new Color(0, 0, 0, 0)); f[0].setVisible(true); }); Thread.sleep(200); EventQueue.invokeAndWait(() -> { f[0].dispose(); }); } EventQueue.invokeAndWait(() -> { JFrame frame = new JFrame("dummy"); frame.setSize(100, 100); frame.setVisible(true); }); } }
13-08-2014

I can reproduce this problem. I'm using the jVisualVM tool and I can see multiple instances of JLightweightFrame objects not being GC'ed.
13-08-2014