8000 large memory usage · Issue #879 · knowm/XChart · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
large memory usage #879
Open
Open
@flavius-t

Description

@flavius-t

Describe the bug
XChart seems to be using a larger amount of memory than expected, i.e. compared to JFreeChart.

To Reproduce
I coded two simple examples, where clicking a button adds X number of data points to an XY chart (i.e. X=18000 to represent one sample per second for 5 hours). One example uses XChart and the other uses JFreeChart.

I used VisualVm to monitor the heap usage before and after adding the data points. I included the screenshots below. For each test, I clicked the button to add the data 5 times, each click roughly 10 seconds apart.

XChart Example

package org.example;

import org.knowm.xchart.QuickChart;
import org.knowm.xchart.XChartPanel;
import org.knowm.xchart.XYChart;

import javax.swing.JButton;
import javax.swing.JFrame;
import java.awt.Color;

public class SingleShotExampleXChart {
    public static final int NUM_DATA_POINTS = 18000;

    public static void main(String[] args) {
        double[] xData = new double[NUM_DATA_POINTS];
        double[] yData = new double[NUM_DATA_POINTS];

        final XYChart chart = QuickChart.getChart("Simple XChart Demo", "Time (ms)", "Y", "mockData", xData, yData);
        XChartPanel<XYChart> chartPanel = new XChartPanel<>(chart);

        JFrame frame = new JFrame("XChart Example");

        long timestamp = System.currentTimeMillis();
        for (int i = 0; i < NUM_DATA_POINTS; i++) {
            yData[i] = Math.random() * 100;
            xData[i] = timestamp + i;
        }

        JButton button = new JButton("Add New Data");
        button.addActionListener(e -> {
            Color randomColor = new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
            chart.getSeriesMap().get("mockData").setMarkerColor(randomColor);
            chart.getSeriesMap().get("mockData").setLineColor(randomColor);
            chart.getSeriesMap().get("mockData").setFillColor(randomColor);
            javax.swing.SwingUtilities.invokeLater(() -> {
                chart.updateXYSeries("mockData", xData, yData, null);
                chartPanel.repaint();
            });
        });

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new java.awt.BorderLayout());
        frame.add(button, java.awt.BorderLayout.SOUTH);
        frame.add(chartPanel, java.awt.BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}

JFreeChart Example

package org.example;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import javax.swing.JButton;
import javax.swing.JFrame;
import java.awt.BorderLayout;
import java.awt.Color;

public class SingleShotJFreeChart {
    public static final int NUM_DATA_POINTS = 18000;

    public static void main(String[] args) {
        double[] xData = new double[NUM_DATA_POINTS];
        double[] yData = new double[NUM_DATA_POINTS];

        long timestamp = System.currentTimeMillis();
        for (int i = 0; i < NUM_DATA_POINTS; i++) {
            yData[i] = Math.random() * 100;
            xData[i] = timestamp + i;
        }

        XYSeries series = new XYSeries("mockData");
        XYSeriesCollection dataset = new XYSeriesCollection(series);

        JFreeChart chart = ChartFactory.createXYLineChart(
                "Simple JFreeChart Demo",
                "Time (ms)",
                "Y",
                dataset,
                PlotOrientation.VERTICAL,
                true,
                true,
                false
        );

        XYPlot plot = chart.getXYPlot();
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
        plot.setRenderer(renderer);

        ChartPanel chartPanel = new ChartPanel(chart);

        JFrame frame = new JFrame("JFreeChart Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        JButton button = new JButton("Add New Data");
        button.addActionListener(e -> {
            Color randomColor = new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
            renderer.setSeriesPaint(0, randomColor);
            plot.setRenderer(renderer);
            javax.swing.SwingUtilities.invokeLater(() -> {
                series.clear();
                for (int i = 0; i < NUM_DATA_POINTS; i++) {
                    series.add(xData[i], yData[i]);
                }
                chartPanel.repaint();
            });
        });

        frame.add(button, BorderLayout.SOUTH);
        frame.add(chartPanel, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}

Screenshots

XChart

image

JFreeChart

image

Expected behavior
You can see from the screenshots, XChart is using several times more memory than JFreeChart: up to 1.25 GB at the peak. Eventually, it looks like garbage collection kicks in, but even at this point XChart is using around 210 MB while JFreeChart is around 42 MB. Note, if I manually trigger garbage collection, the memory usage in XChart drops to negligible levels (~10 MB)

image

It seems unexpected for XChart to be using that amount of memory; ideally less memory would be needed.

Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0