Memory Leak issue

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Post Reply
FourW Support
Posts: 6
Joined: Mon Jan 14, 2019 3:17 pm
antibot: No, of course not.

Memory Leak issue

Post by FourW Support » Fri Jan 18, 2019 4:05 pm

Hi we are new to JFreeChart,
We are using JFreeChart for showing bar chart inside Table cell using chartPanel in TableCell Renderer class in our Java swing application. Our requirement is to update the chart for every four seconds for minimum of 100 rows. Here we are facing memory leackage issue. The heap memory is growing linearly. Help us out to solve this issue.

We are using JFreeChart 1.0.19 version.

Thanks,
4W Support.

John Matthews
Posts: 464
Joined: Wed Sep 12, 2007 3:18 pm

Re: Memory Leak issue

Post by John Matthews » Sat Jan 19, 2019 1:29 pm

Several strategies are examined here.

FourW Support
Posts: 6
Joined: Mon Jan 14, 2019 3:17 pm
antibot: No, of course not.

Re: Memory Leak issue

Post by FourW Support » Tue Jan 22, 2019 11:01 am

Thanks For your response...
The Link you referred is not related to our scenario. Here we attach a code snippet which explain our exact scenario.
In this scenario the Heap memory is linearly increases up-to 1 GB and so on , without the renderer call heap memory is stable at 20MB.
can you please advice on this scenario.

Code: Select all

Class ThreadSample Extends Thread{
	@Override
	public void run() {
		do{
			function();
			try {
				Thread.sleep(4000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}while(true);
	}
	function(){
		for (int i = 0; i < 100; i++) { //100 is minimum row count this might be more than 600.
			for (int j = 0; j < 20; j++) {
				/*
				*Here mainClass.Table is an static JTable from main class.
				*/
				if(mainClass.Table.getTableHeader().getColumnModel().getColumn(j).getHeaderValue().toString().contains("graph"){
					TableCellRenderer tr = new GraphCellRenderer(i,j);
					mainClass.Table.getColumnModel().getColumn(j).setCellRenderer(tr);
				}
			}
		}
	}
}
class GraphCellRenderer implements TableCellRenderer {
	public static String[] time = { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100", "110", "120", "130",
			"140", "150", "160", "170", "180", "190", "200" };
	public static DefaultCategoryDataset gData = new DefaultCategoryDataset();
	public static int row, col;
	public static int maxLimit=100;
	static int rowValue;
	GraphCellRenderer(int rowdummy, int column) {
		row = rowdummy;
		col = column;
		//System.out.println("column" + column + "row" + row);
	}
	
	@SuppressWarnings("unused")
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
			int row2, int column) {
		rowValue=row2;
		JFreeChart chart = null;
		ChartPanel chartPanel = null;
		CategoryPlot plot = null;
		for(int i=0;i<row;i++) {
			if (i==row2) {
				chart = ChartFactory.createBarChart("", "", "", getData(row2, column), 					PlotOrientation.VERTICAL,false, false, true);
				chartPanel = new ChartPanel(chart);
				plot = (CategoryPlot) chart.getPlot();
				chart = null;
				plot.setBackgroundPaint(Color.white);
				plot.setOutlinePaint(null);
				plot.getDomainAxis().setCategoryMargin(0.08);
				BarRenderer renderer = (BarRenderer) plot.getRenderer();
				CategoryItemRenderer renderer1 = new CustomRenderer(
					new Paint[] { Color.red, Color.magenta, Color.green, 
							  Color.red, Color.magenta, Color.magenta,
						Color.green, Color.red, Color.magenta, 
						Color.red, Color.green, Color.red, Color.magenta,
						Color.green, Color.red, Color.magenta, 
						Color.magenta, Color.green, Color.red ,Color.red});
				plot.setRenderer(renderer1);
				renderer1 = null;
				CategoryAxis numberaxis = (CategoryAxis) plot.getDomainAxis();
				numberaxis.setVisible(false);
				NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
				rangeAxis.setRange(0, maxLimit);
				rangeAxis.setVisible(false);
				rangeAxis.setTickMarksVisible(false);
				ValueMarker Normal = new ValueMarker(300);
				Normal.setPaint(Color.GREEN);
				final IntervalMarker target = new IntervalMarker(50.0, 60.0);
				final IntervalMarker target1 = new IntervalMarker(70.0, 80.0);
				final IntervalMarker target2 = new IntervalMarker(80.0, 90.0);
				return chartPanel;
			}
		}
		return null;
	}

	public static  DefaultCategoryDataset getData(int row2, int column) {
		for (int ii = 0; ii <= row; ii++) {
			if (row2 == ii) {
				gData.clear();
				for (int i = 0; i < 20; i++) {
					if (i==0){
						/*
						*mainClass.value is an int[] array from another class.
						*which has values of each bar.
						*/
						int mLim=mainClass.value[row2][i];
						if (mLim!=0)
							maxLimit=mLim;
						continue;
					}
					gData.addValue(mainClass.value[row2][i], "", time[i-1]);
				}
				return gData;
			}
		}
		return null;
	}
}

class CustomRenderer extends BarRenderer {
	private static final long serialVersionUID = 1L;
	private Paint[] colors;
	public CustomRenderer(Paint[] colors) {
		for (int i=0;i<20;i++){
			if(mainClass.dummyColor[GraphCellRenderer.rowValue][i]!=null) {
				try {
					/*
					*mainClass.dummyColor[][] is an static Paint[][] array from another class
					* which has color values of each bar
					*/
					colors[i]=mainClass.dummyColor[GraphCellRenderer.rowValue][i]; 
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}
		this.colors = colors;
	}
	public Paint getItemPaint(final int row, final int column) {
		return this.colors[column % this.colors.length];
	}
}

John Matthews
Posts: 464
Joined: Wed Sep 12, 2007 3:18 pm

Re: Memory Leak issue

Post by John Matthews » Tue Jan 22, 2019 7:23 pm

Your fragment is incorrectly synchronized: it updates a GUI component from a thread other than the event dispatch thread; the approach shown here may be appropriate. In addition, it is unclear why the TableCellRenderer is re-creating the entire chart with each invocation. Each chart should be created once during initialization; each chart's dataset should be updated only on the event dispatch thread; and the TableCellRenderer should return only the chart panel for the row and column specified in the implementation's signature.

Post Reply