Memory Leak

A discussion forum for FXGraphics2D (adds a Java2D API to the JavaFX Canvas).
Locked
bdschubert
Posts: 7
Joined: Wed May 21, 2014 3:57 pm
antibot: No, of course not.

Memory Leak

Post by bdschubert » Wed Jul 16, 2014 4:05 pm

I'm experiencing a severe memory leak whenever I (re)draw the FXGraphics2D based ChartCanvas. This behavior can be replicated in the FXGraphics2DDemo1 by running it within a profiler ( NetBeans 8 ) and resizing the chart with the mouse. Or, you can add the following test code to the demo's start method for a repeatable test that really exposes the problem:

Code: Select all

   public void start(Stage stage) throws Exception {
        // ....
        stage.show();

        // Test Memory Leak
        Thread t = new Thread(() -> {
            try {
                for (int i = 0; i < 10000; i++) {
                    Thread.sleep(10);
                    Platform.runLater(() -> {
                        canvas.draw();
                    });
                }
            }
            catch (InterruptedException ex) {
            }
        });
        t.start();
}
BTW: try resizing the chart a few times after above loop is finished and watch the heap grow from 500MB to > 1.5GB.
The most offending objects are a byte array and com.sun.prism.paint.Color object.
-- Bruce

bdschubert
Posts: 7
Joined: Wed May 21, 2014 3:57 pm
antibot: No, of course not.

Re: Memory Leak

Post by bdschubert » Wed Jul 16, 2014 8:29 pm

This is my first foray into JavaFX, so I may be ignorant on how things work, or are supposed to work, but regardless, here's what I've discovered thus far:
  • It appears that when a chart makes a graphics call into FXGraphics2D, the GraphicsContext (gc) member appends data to its GrowableDataBuffer()
  • Checkout: FXGraphics2D.setColor() -> gc.setStroke() -> GraphicsContent.writePaint() -> GrowableDataBuffer.putObject()
  • I can't find where this buffer is ever cleared, except thru an explicit called to gc.clearRect(), which will perform a conditional reset.
Should the ChartCanvas be a transient object (re)created whenever the chart content changes?
-- Bruce

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: Memory Leak

Post by david.gilbert » Thu Jul 17, 2014 9:00 am

I wasn't able to reproduce this leak, so my first guess is that it is platform dependent. Which JDK version and OS are you using? I tested with JDK 1.8.0_05 on a Mac and garbage collection looks fine.

Your note about clearRect() is something I had read about also and I *thought* that I had put a clearRect() in the code, but it doesn't appear to be there. Perhaps the solid fill when drawing the chart background is sufficient to trigger disposal of the queue? Anyway, the first step for me will be to reproduce the issue, so I'll focus on that first.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

bdschubert
Posts: 7
Joined: Wed May 21, 2014 3:57 pm
antibot: No, of course not.

Re: Memory Leak

Post by bdschubert » Thu Jul 17, 2014 2:09 pm

I'm using JDK8 1.8.0; Windows8 64bit.
I'll try JDK8_u11 and report back.
-- Bruce

bdschubert
Posts: 7
Joined: Wed May 21, 2014 3:57 pm
antibot: No, of course not.

Re: Memory Leak

Post by bdschubert » Thu Jul 17, 2014 3:19 pm

No change with JDK8 u11 on Windows8 64bit. :( For reference, I'm using the most recent code from https://github.com/jfree/fxgraphics2d.

Here's some screenshots of the Profiler with and without using clearRect:

1.5GB Memory usage without clearRect
jfreefx_demo.png

250MB Memory usage with clearRect (note, memory consumption continues to grow when you resize the chart, but not as fast).
jfreefx_demo_clearrect.png

For reference, here's the modified demo code:
draw() method with clearRect

Code: Select all

        private void draw() {
            double width = getWidth();
            double height = getHeight();
            
            GraphicsContext gc = this.getGraphicsContext2D();
            gc.clearRect(0, 0, width, height);
            
            this.chart.draw(this.g2, new Rectangle2D.Double(0, 0, width, height));
        }
start() method with test code

Code: Select all

    @Override
    public void start(Stage stage) throws Exception {
        XYDataset dataset = createDataset();
        JFreeChart chart = createChart(dataset);
        ChartCanvas canvas = new ChartCanvas(chart);
        StackPane stackPane = new StackPane();
        stackPane.getChildren().add(canvas);
        // Bind canvas size to stack pane size. 
        canvas.widthProperty().bind(stackPane.widthProperty());
        canvas.heightProperty().bind(stackPane.heightProperty());
        stage.setScene(new Scene(stackPane));
        stage.setTitle("FXGraphics2DDemo1.java");
        stage.setWidth(700);
        stage.setHeight(390);
        stage.show();

        Thread t = new Thread(() -> {
            try {
                for (int i = 0; i < 10000; i++) {
                    Thread.sleep(10);
                    Platform.runLater(() -> {
                        canvas.draw();
                    });
                }
            }
            catch (InterruptedException ex) {
            }
        });
        t.start();
    }
-- Bruce

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: Memory Leak

Post by david.gilbert » Sun Jul 20, 2014 10:17 am

Hi Bruce,

In the end I did reproduce this on my Mac (and also a Windows machine), I didn't see memory usage as high as you but still around 250meg. Definitely the clearRect() is the right thing to add. After that, I can set the max heap to 10meg and it runs fine even if the garbage collector gets busy.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

bdschubert
Posts: 7
Joined: Wed May 21, 2014 3:57 pm
antibot: No, of course not.

Re: Memory Leak

Post by bdschubert » Mon Jul 21, 2014 10:47 pm

10MB! That's really encouraging. I wonder why my memory consumption is higher. I was testing with the libs from the Git distribution (jfreechart 1.0.17). Are you using the same in your tests?
-- Bruce

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: Memory Leak

Post by david.gilbert » Wed Jul 30, 2014 9:59 pm

I made a new release just now, let me know if you still see the memory leaking behavior. I'm hopeful that the addition of the clearRect() call is enough to fix it, it certainly improves the behavior on the systems I tested. However, it is possible that it behaves differently on other platforms (and I didn't get to test Windows 8).
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

Locked