0

私は初めてJFreeChartを使用しており、TimeSeriesCollection()を使用してTimeSeriesChartを作成しています。

DBクエリからの私のreslutsetはアプリです。約1000レコード。org.jfree.date.time.Minute.Minute(int min .....)オブジェクトを使用して、TimeSeriesオブジェクトに追加しています。

ChartPanelを直接追加するJFrameがあります。ユーザーは新しい入力パラメーターを提供し、チャートデータに新しいデータセットを再読み込みします。だから私はメソッドで以下を呼び出すことによってすべてのリロードの前にクリーンアップします

            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.<init>(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)

私のアプリケーションは次のとおりです。

チャートを渡した後、ChartPanelを直接追加するJFrameがあります。

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<Qryobjects> 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;
}
4

5 に答える 5

3

参考までに、2 つの長期実行時系列DTSCTestとをプロファイリングしましMemoryUsageDemoた。スケールを誇張するために、以下に示すように人為的に小さなヒープを使用しました。いずれの場合も、ここに示すように、定期的なガベージ コレクションの典型的な鋸歯状のパターンがベースラインに戻ることがわかりました。対照的に、この病的な例は、回復不能なリソースによる消費メモリの長期的な増加を示しています。

$ java -Xms32m -Xmx80m -cp build/classes:dist/lib/* chart.DTSCTest
$ java -Xms32m -Xmx80m -jar jfreechart-1.0.14-demo.jar
于 2013-03-09T04:45:53.987 に答える
1

問題を解決しました。

@TrashGod からヒントを得て、dispose() を使用しました。しかし、それは私にとって直接には機能しません。

グラフ パネルをメインの JFrame コンテナに直接追加していました。そして私の場合、同じ JFrame コンテナー内にチャートを何度も作成し続けたいと考えていました。

最初にデータセットのクリアを試み、チャート パネルで removeall() を呼び出しましたが、役に立ちませんでした。

それから私が見つけた解決策は、別の JFrame を作成し、それにグラフ パネルを追加することでした。そして、この JFrame を閉じると、データセットを再びクリアし、チャート パネルで removeall() を呼び出し、さらに dispose() も呼び出しました。したがって、毎回新しいチャートを作成すると、この JFrame とその子コンポーネントが作成され、この JFrame を終了すると完全に破棄されます。

そのため、チャートが作成されると、新しい JFrame が作成されてから破棄されます。

また、この変更を行った後、Java VisualVM プロファイラーに Saw Tooth パターンが表示されるようになったことも付け加えておきます。Jprofiler も使用しましたが、プログラムの実行中に 100,000 を超えるオブジェクトが作成されたことにショックを受けました。現在、9000 個のオブジェクトが作成されており、JFree パッケージでは一定のままであり、取得した結果セットに基づいて、データベース パッケージ内のオブジェクトの数が増減します。

私が行ったもう 1 つのことは、SQL に解析を実行させ、それを数値に変換することでした。作成されるオブジェクトの数を減らし、取得したレコードごとにプログラムが行う処理も減らしたいと考えていました。

于 2013-03-13T18:13:23.207 に答える
0

メソッド org.jfree.chart.axis.DateAxis.refreshTicksHorizo​​ntal で、OutOfmemoryError を正常に回避するために次の行を追加しました。なぜかというと、変数 tickDate が増えていないため、「while (tickDate.before(upperDate))」のループが無限ループになってしまうからです。

protected List refreshTicksHorizontal(Graphics2D g2,
            Rectangle2D dataArea, RectangleEdge edge) {

    List result = new java.util.ArrayList();

    Font tickLabelFont = getTickLabelFont();
    g2.setFont(tickLabelFont);

    if (isAutoTickUnitSelection()) {
        selectAutoTickUnit(g2, dataArea, edge);
    }

    DateTickUnit unit = getTickUnit();
    Date tickDate = calculateLowestVisibleTickValue(unit);
    Date upperDate = getMaximumDate();

    boolean hasRolled = false;
    Date previousTickDate=null;            //added 
    while (tickDate.before(upperDate)) {
        if(previousTickDate!=null && tickDate.getTime()<=previousTickDate.getTime()){  //added 
            tickDate=new Date(tickDate.getTime()+100L); //added 
        }  //added 
        previousTickDate=tickDate; //added 
        //System.out.println("tickDate="+tickDate+" upperDate="+upperDate);**  //add to see infinite loop
于 2013-07-10T16:44:26.870 に答える
0

チャートからツールチップと凡例を削除してみてください (コンストラクターで「false」にします)。メモリフットプリントを削減する必要があります

于 2020-01-29T16:14:20.317 に答える