JFreeChart - Java 堆空间问题

21 浏览
0 Comments

JFreeChart - Java 堆空间问题

我第一次使用JFreeChart,使用TimeSeriesCollection()来创建TimeSeriesChart。

我的DB查询结果约有1000条记录。我使用org.jfree.date.time.Minute.Minute(int min .....)对象将其添加到TimeSeries对象中。

我有一个JFrame,在其中直接添加ChartPanel。用户将提供新的输入参数,并使用新的数据集重新加载图表数据。因此,在每次<强>重新加载之前,我通过在方法中调用以下内容进行清理

            dataset.removeAllSeries();
            chart.removeLegend();
            chart.getRenderingHints().clear();
            cp.getChartRenderingInfo().setEntityCollection(null);
            cp.removeAll();
            cp.revalidate();

输出结果很完美。但我注意到,在Eclipse中运行程序“几次”后,我会看到以下关于Java堆空间的错误消息。有时,即使数据集非常小(100个记录),也可以看到程序在PC内存上占用资源。

Exception occurred during event dispatching:
java.lang.OutOfMemoryError: Java heap space
at sun.util.calendar.Gregorian.newCalendarDate(Gregorian.java:67)
at java.util.GregorianCalendar.(GregorianCalendar.java:575)
at java.util.Calendar.createCalendar(Calendar.java:1012)
at java.util.Calendar.getInstance(Calendar.java:964)
at org.jfree.chart.axis.DateTickUnit.addToDate(DateTickUnit.java:238)
at org.jfree.chart.axis.DateAxis.refreshTicksHorizontal(DateAxis.java:1685)
at org.jfree.chart.axis.DateAxis.refreshTicks(DateAxis.java:1556)
at org.jfree.chart.axis.ValueAxis.reserveSpace(ValueAxis.java:809)
at org.jfree.chart.plot.XYPlot.calculateDomainAxisSpace(XYPlot.java:3119)
at org.jfree.chart.plot.XYPlot.calculateAxisSpace(XYPlot.java:3077)
at org.jfree.chart.plot.XYPlot.draw(XYPlot.java:3220)
at org.jfree.chart.JFreeChart.draw(JFreeChart.java:1237)
at org.jfree.chart.ChartPanel.paintComponent(ChartPanel.java:1677)
at javax.swing.JComponent.paint(JComponent.java:1029)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5124)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1491)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1422)
at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:294)
at javax.swing.RepaintManager.paint(RepaintManager.java:1225)
at javax.swing.JComponent._paintImmediately(JComponent.java:5072)
at javax.swing.JComponent.paintImmediately(JComponent.java:4882)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:786)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:714)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:694)
at javax.swing.RepaintManager.access$700(RepaintManager.java:41)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1636)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:646)
at java.awt.EventQueue.access$000(EventQueue.java:84)
at java.awt.EventQueue$1.run(EventQueue.java:607)
at java.awt.EventQueue$1.run(EventQueue.java:605)
at java.security.AccessController.doPrivileged(Native Method)

我的应用程序如下:

我有一个JFrame,在其中传递了一个Chart后直接添加ChartPanel。

chart = ChartFactory.createTimeSeriesChart("Peak monitor", , "Time: Zoom in", "# of Requests Logged", createDataset(from,to), true, false, false);
            chartpanel = new ChartPanel(chart);
            FramePanel.this.add(cp);
            validate();

这里createDataset(from,to)是一个方法

 private TimeSeriesCollection createDataset(Date from, Date to) {
    dataset.addSeries(controller.getStuff(from, to));
    return dataset;
}

getStuff在SwingWorker线程(DIBkgd方法)中被调用

 public TimeSeries getStuff(Date from, Date to) {
    s1 = new TimeSeries("Log Requests");
    final Date from1 = from;
    final Date to1 = to;
    progressDialog.setVisible(true);
    sw = new SwingWorker<Void, Integer>() {
        @Override
        protected Void doInBackground() throws Exception {
            if (db.getCon() == null) {
                db.connect();
            }
            Arrlst2.clear();
            Arrlst2= db.getDataDB(from1, to1);
            for (Qryobjects x : Arrlst2) {                  
              s1.add(new Minute(x.getMinute(), x.getHour(), x.getDay(), x.getMonth(), x.getYear()), x.getCount());
            }
            System.out.println("finished fetching data");
            return null;
        }
        @Override
        protected void done() {
            progressDialog.setVisible(false);
        }
    };
    sw.execute();
    return s1;
}

在我的数据库类中,执行getDataDB:

 public List getDataDB(Date from, Date to) {
    PreparedStatement select;
    ResultSet rs;
    String selectSql = "Select Sum(Cnt) Cid, Hr, Min, Dat from (Select count(H.Request_Id) Cnt , To_Char(H.Timestamp,'HH24') HR, To_Char(H.Timestamp,'mm') MIN, To_Char(H.Timestamp,'MM-dd-yyyy') DAT From Status_History H Where H.Timestamp Between ? And ? Group By  H.Request_Id,  H.Timestamp Order By H.Timestamp Asc) Group By Hr, Min, Dat order by Dat asc";
    try {
        select = con.prepareStatement(selectSql);
        select.setDate(1, from);
        select.setDate(2, to);
        rs = select.executeQuery();
        System.setProperty("true", "true");
        while (rs.next()) {
            int cnt = rs.getInt("cid");
            int hour = Integer.parseInt(rs.getString("Hr"));
            int min = Integer.parseInt(rs.getString("Min"));
            int month = Integer.parseInt(rs.getString("dat").substring(0, 2));
             int day = Integer.parseInt(rs.getString("dat").substring(3, 5));
            int year = Integer.parseInt(rs.getString("dat").substring(6, 10));
             Arrlst1.add(new Qryobjects(cnt, hour, min, day, month,year));
        }
        rs.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return Arrlst1;
}

admin 更改状态以发布 2023年5月21日
0
0 Comments

我解决了我的问题。

我从 @TrashGod 那里得到了提示,要使用dispose()方法。但直接使用并没有起作用。

我直接将图表面板添加到主体JFrame容器中。在我的情况下,我想要在同一个JFrame容器中一遍又一遍地创建图表。

我首先尝试清除数据集并在图表面板上调用removeall(),但没有帮助。

后来我找到的解决方案是创建另一个JFrame并将图表面板添加到其中。当我关闭这个JFrame时,我再次清除数据集并在图表面板上调用removeall(),还调用了dispose()。因此,每次我创建一个新的图表时,都会创建这个JFrame及其子组件,并且在退出此JFrame时完全被销毁。

因此,当创建一个图表时,会创建一个新的JFrame,然后将其销毁。

我还应该补充一点,在进行这些更改后,我开始在Java VisualVM分析器中看到锯齿状模式。我还使用了Jprofiler,惊讶地发现在运行程序时创建了超过100,000个对象。现在,我看到创建的对象数为9000,并且对于JFree程序包,它保持恒定,基于我检索的结果集,我的数据库程序包中对象的数量会增加或减少。

我还做的一件事是使我的SQL进行解析并将其转换为数字。我想减少创建的对象数,减少程序为检索到的每个记录所做的处理。

0
0 Comments

供参考,我对两个长时间序列 DTSCTestMemoryUsageDemo 进行了性能剖析。为了夸大其规模,我使用了一个人为的小堆,如下所示。在每种情况下,我看到了周期性垃圾收集的典型锯齿形模式返回到基线,如此处所示。相比之下,这个例子显示了未从资源中恢复的消耗内存的长期上升。

$ java -Xms32m -Xmx80m -cp build/classes:dist/lib/* chart.DTSCTest
$ java -Xms32m -Xmx80m -jar jfreechart-1.0.14-demo.jar
0