Memory Leak

A discussion forum for FXGraphics2D (adds a Java2D API to the JavaFX Canvas).

Memory Leak

Postby 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

Re: Memory Leak

Postby 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
bdschubert
 
Posts: 7
Joined: Wed May 21, 2014 3:57 pm

Re: Memory Leak

Postby 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: Ask your company to buy the JFreeChart Developer Guide
:idea: Check out other products sold by my company Object Refinery Limited
david.gilbert
JFreeChart Project Leader
 
Posts: 11622
Joined: Fri Mar 14, 2003 10:29 am

Re: Memory Leak

Postby 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

Re: Memory Leak

Postby 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
bdschubert
 
Posts: 7
Joined: Wed May 21, 2014 3:57 pm

Re: Memory Leak

Postby 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: Ask your company to buy the JFreeChart Developer Guide
:idea: Check out other products sold by my company Object Refinery Limited
david.gilbert
JFreeChart Project Leader
 
Posts: 11622
Joined: Fri Mar 14, 2003 10:29 am

Re: Memory Leak

Postby 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
bdschubert
 
Posts: 7
Joined: Wed May 21, 2014 3:57 pm

Re: Memory Leak

Postby 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: Ask your company to buy the JFreeChart Developer Guide
:idea: Check out other products sold by my company Object Refinery Limited
david.gilbert
JFreeChart Project Leader
 
Posts: 11622
Joined: Fri Mar 14, 2003 10:29 am


Return to FXGraphics2D

Who is online

Users browsing this forum: No registered users and 1 guest