我试图用新数据每隔几秒重绘一次JFreeChart系列。重绘正在自己的线程中进行。一切正常,但清除系列会导致奇怪的内存泄漏。
我不确定问题是来自sleeping the thread还是clear()方法中的任何错误。
这是完整的示例代码(方法SampleDataFeed中有问题的行):
import java.util.Calendar;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.time.FixedMillisecond;
import org.jfree.data.time.ohlc.OHLCSeries;
import org.jfree.data.time.ohlc.OHLCSeriesCollection;
public class sample1 {
private static OHLCSeries series1;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// window
JFrame wnd = new JFrame();
wnd.setVisible(true);
wnd.setSize(800, 500);
wnd.setLocationRelativeTo(null);
wnd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// chart series
OHLCSeries series = new OHLCSeries("Test");
OHLCSeriesCollection seriesCollection = new OHLCSeriesCollection();
seriesCollection.addSeries(series);
series1 = seriesCollection.getSeries(0);
// chart
final JFreeChart chart = ChartFactory.createCandlestickChart(null, "Time", "Price", seriesCollection, false);
chart.getXYPlot().setOrientation(PlotOrientation.VERTICAL);
// chart panel
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setMaximumDrawHeight(2000);
chartPanel.setMaximumDrawWidth(3000);
wnd.add(chartPanel);
// chart data feeding thread
new DataFeedingThread().start();
}
});
}
private static class DataFeedingThread implements Runnable {
private Thread t;
@Override
public void run() {
// run recursively
while (true) {
// feed the chart with random data
SampleDataFeed();
// what 1 second before next run
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// feed the chart with random data
private void SampleDataFeed() {
series1.clear(); // -----> This line causes memory leak! If I'd comment it, everything is Ok.
for (int i = 0; i < 100; i++) {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, i);
FixedMillisecond fm = new FixedMillisecond(cal.getTime());
series1.add(fm, randInt(95, 105), randInt(105, 110), randInt(90, 95), randInt(95, 105));
}
}
// return random integer
private int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
public void start() {
if (t == null) {
t = new Thread(this);
t.start();
}
}
}
}
更新
JFreeChart版本:1.0.19
编译器选项:无
内存使用不清除~15-30 MB :
内存使用清除~430MB并提升:
答案 0 :(得分:1)
我发现删除所有系列的集合然后添加新的准备系列数据就是解决方案(bug?)。
这是我的新代码:
import java.util.Calendar;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.time.FixedMillisecond;
import org.jfree.data.time.ohlc.OHLCSeries;
import org.jfree.data.time.ohlc.OHLCSeriesCollection;
public class sample1 {
private static final OHLCSeriesCollection seriesCollection = new OHLCSeriesCollection();
private static final DataFeedingThread dataFeedingThread = new DataFeedingThread();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAll();
}
});
}
public static void createAll() {
// window
JFrame wnd = new JFrame();
wnd.setVisible(true);
wnd.setSize(800, 500);
wnd.setLocationRelativeTo(null);
wnd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// chart series
seriesCollection.addSeries(new OHLCSeries("Test"));
// chart
final JFreeChart chart = ChartFactory.createCandlestickChart(null, "Time", "Price", seriesCollection, false);
chart.getXYPlot().setOrientation(PlotOrientation.VERTICAL);
// chart panel
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setMaximumDrawHeight(2000);
chartPanel.setMaximumDrawWidth(3000);
wnd.add(chartPanel);
// chart data feeding thread
dataFeedingThread.start();
}
public static void setOHLCSeries(OHLCSeries series) {
seriesCollection.removeAllSeries();
seriesCollection.addSeries(series);
}
private static class DataFeedingThread implements Runnable {
private Thread t;
@Override
public void run() {
// run recursively
while (true) {
// feed the chart with random data
SampleDataFeed();
// what 1 second before next run
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// feed the chart with random data
private void SampleDataFeed() {
OHLCSeries series = new OHLCSeries("test");
for (int i = 0; i < 100; i++) {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, i);
FixedMillisecond fm = new FixedMillisecond(cal.getTime());
series.add(fm, randInt(95, 105), randInt(105, 110), randInt(90, 95), randInt(95, 105));
}
setOHLCSeries(series);
}
// return random integer
private int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
public void start() {
if (t == null) {
t = new Thread(this);
t.start();
}
}
}
}
在上面的代码中,我删除了图表中的所有系列并添加了新的系列(包含准备好的数据)。这就是全部,一切正常。
以下是内存分析:
如您所见,所有应用程序的消耗都不超过110 MB。
更新1:
事实上,上面的例子没有解决问题。在很多情况下会出现这种错误。我有很多小时测试并找到内存泄漏问题的最终解决方案。 唯一可能的是JFreeGhart中的#1111 bug。开放时间超过一年。 Mr. Gilber你可以解决这个问题吗?如果它能在短期内完成,我愿意为你付钱。
感谢。