Dynamic Chart [ Memory problem... ]

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
reji

Dynamic Chart [ Memory problem... ]

Post by reji » Wed Nov 13, 2002 12:12 pm

Hi,

I am using JFreeChart in an application and found the following problem..

Test Environment : Win2K, JDK1.3.1

JFreeChart 0.9.4 , JCommon 0.7.1

I am simulating a Monitor Panel with SwingWorker class.. Found memory usage is keep on increasing.. till I get OutOfMemory error..

Test files attached here with...

Any suggestions.......??

Thanks in advance...

-----------------------------------------------------------------
MonitorFrame.java
-----------------------------------------------------------------

package testmemory;

import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JFrame;
public class MonitorFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Monitor Panel");
MyChartPanel panel = new MyChartPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.setSize(800, 800);
frame.setVisible(true);
frame.pack();
}
}
-------------------------------------------------------------------
MyChartPanel.java
-------------------------------------------------------------------
package testmemory;

import java.util.Date;
import java.awt.*;
import javax.swing.*;
import com.jrefinery.chart.*;
import com.jrefinery.data.*;
public class MyChartPanel extends JPanel
{
private JPanel mainPnl = new JPanel(new GridLayout(3, 3, 5, 5));

private ChartPanel[] cpanel = new ChartPanel[9];
private JFreeChart[] charts = new JFreeChart[9];
private XYDataset[] dsets = new XYDataset[9];

private BasicTimeSeries[] series = new BasicTimeSeries[9];
private TimeSeriesCollection[] coll = new TimeSeriesCollection[9];

private SwingWorker worker = null;
private boolean active = true;
private int counter= 0;

public MyChartPanel()
{
for(int x=0; x< 9; x++)
{
series[x] = new BasicTimeSeries("Series"+x, Millisecond.class);
coll[x] = new TimeSeriesCollection();
coll[x].addSeries(series[x]);
dsets[x] = coll[x];
charts[x] = ChartFactory.createTimeSeriesChart("Chart "+x,"","",dsets[x],true);
cpanel[x] = new ChartPanel(charts[x]);
cpanel[x].setPreferredSize(new Dimension(250, 200));
mainPnl.add(cpanel[x]);
}
this.add(mainPnl, BorderLayout.CENTER);

worker = new SwingWorker()
{
public Object construct()
{
return startWorker();
}
};
worker.start();
}

private Object startWorker()
{

while(active)
{
try
{
updateChartDatasets();
updateMonitorCharts();
if (Thread.interrupted())
{
throw new InterruptedException();
}
Thread.sleep((long)2000);
counter++;
}
catch(Exception exp)
{
exp.printStackTrace();
}
}
return "Done";
}

private void updateChartDatasets()
{
Date currTime = new Date();
double value = Math.random();
for(int x=0; x<9; x++)
updateSeries(series[x], currTime, value);
}

private void updateSeries(BasicTimeSeries series, Date time, double value)
{
if(counter > 20)
series.delete(series.getTimePeriod(0));
series.add(new Millisecond(time), new Double(value));
}

private void updateMonitorCharts()
{
try
{
Runnable doUpdateTime = new Runnable()
{
public void run()
{
for(int x=0; x<9; x++)
charts[x].getXYPlot().setDataset(dsets[x]);
}
};
SwingUtilities.invokeAndWait(doUpdateTime);
}
catch(Exception exp)
{
exp.printStackTrace();
}
}
}

--------------------------------------------------------------
SwingWorker.java
--------------------------------------------------------------
package testmemory;

import javax.swing.SwingUtilities;
public abstract class SwingWorker
{
private Object value = null;
private Thread thread = null;

/**
* Class to maintain reference to current worker thread
* under separate synchronization control.
*/
private static class ThreadVar
{
private Thread thread;
ThreadVar(Thread t) { thread = t; }
synchronized Thread get() { return thread; }
synchronized void clear() { thread = null; }
}

private ThreadVar threadVar;

/**
* Get the value produced by the worker thread, or null if it
* hasn't been constructed yet.
*/
protected synchronized Object getValue()
{
return value;
}

/**
* Set the value produced by worker thread
*/
private synchronized void setValue(Object x)
{
value = x;
}

/**
* Compute the value to be returned by the <code>get</code> method.
*/
public abstract Object construct();

/**
* Called on the event dispatching thread (not on the worker thread)
* after the <code>construct</code> method has returned.
*/
public void finished() { }

/**
* A new method that interrupts the worker thread. Call this method
* to force the worker to stop what it's doing.
*/
public void interrupt()
{
Thread t = threadVar.get();
if (t != null) {
t.interrupt();
}
threadVar.clear();
}

public void join() throws InterruptedException
{
Thread t = threadVar.get();
if(t != null)
{
t.join();
}
}

/**
* Return the value created by the <code>construct</code> method.
* Returns null if either the constructing thread or the current
* thread was interrupted before a value was produced.
*
* @return the value created by the <code>construct</code> method
*/
public Object get()
{
while (true)
{
Thread t = threadVar.get();
if (t == null)
{
return getValue();
}
try
{
t.join();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt(); // propagate
return null;
}
}
}

/**
* Start a thread that will call the <code>construct</code> method
* and then exit.
*/
public SwingWorker()
{
final Runnable doFinished = new Runnable()
{
public void run() { finished(); }
};

Runnable doConstruct = new Runnable()
{
public void run()
{
try
{
setValue(construct());
}
finally
{
threadVar.clear();
}

SwingUtilities.invokeLater(doFinished);
}
};

Thread t = new Thread(doConstruct);
threadVar = new ThreadVar(t);
}

/**
* Start the worker thread.
*/
public void start()
{
Thread t = threadVar.get();
if (t != null)
{
t.start();
}
}
}
------------------------------------------------------------------------

Dave Gilbert

Re: Dynamic Chart [ Memory problem... ]

Post by Dave Gilbert » Thu Nov 14, 2002 12:34 am

Hi Reji,

I'm running your test code now. In MyChartPanel.java I've changed the code slightly. updateMonitorCharts() is redundant, since changing the series refreshes the charts anyway. And I added a line to print out the current memory stats...and also reduced the sleep time to 200, to speed things up:

private Object startWorker() {

while (active) {
try {
updateChartDatasets();
// *** CHANGE ***
//updateMonitorCharts();
System.out.println(Runtime.getRuntime().freeMemory()+"/"
+Runtime.getRuntime().totalMemory());
// *** CHANGE ***
if (Thread.interrupted()) {
throw new InterruptedException();
}
Thread.sleep((long) 200);
counter++;
} catch (Exception exp) {
exp.printStackTrace();
}
}
return "Done";
}

So far, the code is running fine for me on JDK1.3 and Linux. I'll leave it running overnight and see what happens.

Regards,

DG

Dave Gilbert

Re: Dynamic Chart [ Memory problem... ]

Post by Dave Gilbert » Thu Nov 14, 2002 9:39 am

Still running OK this morning. Can you try a different JDK and see if that makes a difference...

Regards,

DG

reji

Re: Dynamic Chart [ Memory problem... ]

Post by reji » Thu Nov 14, 2002 10:07 am

Hi,

I found another thing.. Memory is keep on adding while I am calling Thread.sleep() at the rate of 100KB per 1 second sleep time. Why is it so?

Any idea...?

I have modified the method like this to print the memory usage (KB) before and after Thread.sleep()...


-----------------------------------------------------------------------
private Object startWorker()
{

while(active)
{
try
{
System.out.println("-------------------");
updateChartDatasets();
printMemoryUsage();
if (Thread.interrupted())
{
throw new InterruptedException();
}
Thread.sleep((long)2000);
printMemoryUsage();
counter++;
}
catch(Exception exp)
{
exp.printStackTrace();
}
}
return "Done";
}

private void printMemoryUsage()
{
System.out.println( (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024 );
}
-------------------------------------------------------------------------
regards

reji

Locked