Client side memory leak

Hello.
I have a problem with my Vaadin application. My portlet is using Vaadin 6.7.9, and refresher 1.1.1 add-on for updating client side. Refresher listener calls procedure that parses JSON and updates the graph on client side every few seconds. The graph actually consists of grid and labels. I set the labels to null every time. The problem is that, every time the procedure is called memory size used by browser (firefox, chrome) on client side increases. Eventually the browser uses all the memory. Garbage collection didn’t help.

Here is the procedure:


    GridLayout gl = new GridLayout(3, 2);
    Label[] barImeLabels;
    Label[] barGrafLabels;
    Label[] barProcentLabels;
    Label total = new Label("Total");
    Label totalBar = new Label();
    Label totalProcent = new Label();
    Label opozorilo = new Label("Ni podatkov.");

    private void parseJSONandUpdate(String URLzaXML, Boolean nacrtamTotal, Boolean uredimPoVrednosti) {
    	try {
			URL jsonUrl = new URL(URLzaXML);
			URLConnection jsonUrlConnection = jsonUrl.openConnection();
			InputStream jsonOpenStream = jsonUrlConnection.getInputStream();
			String jsonTxt = /*org.apache.commons.io.*/IOUtils.toString(jsonOpenStream);
			velikostJsonFajla = 0;
			JSONArray vrednosti = null;
			JSONObject json = (JSONObject) JSONSerializer.toJSON(jsonTxt);
		    	vrednosti = json.getJSONArray("vrednosti");
		    	velikostJsonFajla = vrednosti.size();			
			int velikostGrafaUpoštevaTotal;
			barImeLabels = new Label[velikostJsonFajla]
;
			barGrafLabels = new Label[velikostJsonFajla]
;
			barProcentLabels = new Label[velikostJsonFajla]
;
			stringiZaUredit = new String[velikostJsonFajla]
;
			stringiZaPrimerjat = new String[velikostJsonFajla]
;
			double skupniProcenti = 0;
			double količnik = -1;
			JSONObject elementek = null;
			for (int i = 0; i < velikostJsonFajla; i++) {
				elementek = vrednosti.getJSONObject(i);
				if (elementek.opt("ime") != null) {
					barImeLabels[i]
 = new Label(elementek.optString("ime").toString());
					stringiZaUredit[i]
 = elementek.optString("ime").toString();
					stringiZaPrimerjat[i]
 = elementek.optString("ime").toString();
				}	
				barProcentLabels[i]
 = new Label();
				barGrafLabels[i]
 = new Label();	
				if (elementek.opt("vrednost") != null) {
					double vrednost = Double.parseDouble(elementek.opt("vrednost").toString());	
					if (elementek.opt("maximalnaVrednost") != null) {
						if (!elementek.opt("maximalnaVrednost").equals("") && elementek.opt("maximalnaVrednost") !=  Integer.toString(0)) {
							double maximalnaVrednost = Double.parseDouble(elementek.opt("maximalnaVrednost").toString());
							količnik = vrednost/maximalnaVrednost*100;
							skupniProcenti = skupniProcenti + količnik;
							if (elementek.opt("narisiNaGrafu") != null) {
								if ("yes".equals(elementek.opt("narisiNaGrafu").toString())) {
									barGrafLabels[i]
.setValue(kolikoZnakov(vrednost, maximalnaVrednost));
									if (količnik < 90) {
										barGrafLabels[i]
.addStyleName("myStyle0do90");
									} else {
										barGrafLabels[i]
.addStyleName("myStyle90do100");
									}
								}
							}
							barProcentLabels[i]
.setValue(df.format(količnik) + "%");
						} else {
							barProcentLabels[i]
.setValue(Double.toString(vrednost));
						}
					}
				}
			}			
			if (layout.getComponentIndex(opozorilo) != -1) {
				layout.removeComponent(opozorilo);
				opozorilo.detach();
			}
			if  (nacrtamTotal == true) {
				velikostGrafaUpoštevaTotal = velikostJsonFajla + 1;
			} else {
				velikostGrafaUpoštevaTotal = velikostJsonFajla;
			}
			if (layout.getComponentIndex(gl) == -1) {
				parseJSON(URLzaDostop, nacrtamTotal, uredimPoVrednosti);
				for (int i = gl.getRows(); i > velikostGrafaUpoštevaTotal; i--) {
					gl.removeRow(i-1);
				}	
				for (int i = gl.getRows(); i < velikostGrafaUpoštevaTotal; i++) {
					gl.insertRow(i);
				}
			} else {					
				for (int i = gl.getRows(); i > velikostGrafaUpoštevaTotal; i--) {
					gl.removeRow(i-1);
				}
				for (int i = gl.getRows(); i < velikostGrafaUpoštevaTotal; i++) {
					gl.insertRow(i);
				}
				if (uredimPoVrednosti == true) {
					vrstniRed = changeOrder(stringiZaUredit, stringiZaPrimerjat);
				}
				int indeksVrsticeVGridu;
				for (int i = 0; i < velikostJsonFajla; i++) {
					if (uredimPoVrednosti == true) {
						if (nacrtamTotal == true) {
							indeksVrsticeVGridu = vrstniRed[i]
 + 1;
						} else {
							indeksVrsticeVGridu = vrstniRed[i]
;
						}
					} else {
						if (nacrtamTotal == true) {
							indeksVrsticeVGridu = i + 1;
						} else {
							indeksVrsticeVGridu = i;
						}
					}
					if (elementek.opt("ime") != null) {
						gl.removeComponent(0, indeksVrsticeVGridu);
						gl.addComponent(barImeLabels[i]
, 0, indeksVrsticeVGridu);			
					}
					if (elementek.opt("vrednost") != null) {
						if (elementek.opt("narisiNaGrafu") != null) {
							gl.removeComponent(1, indeksVrsticeVGridu);
							gl.addComponent(barGrafLabels[i]
, 1, indeksVrsticeVGridu);
						}
						gl.removeComponent(2, indeksVrsticeVGridu);
						gl.addComponent(barProcentLabels[i]
, 2, indeksVrsticeVGridu);
					}
				}
				if (skupniProcenti < 90) {
					totalBar.setStyleName("myStyle0do90");
				} else {
					totalBar.setStyleName("myStyle90do100");
				}
				total.setStyleName("total0do90");
				totalProcent.setStyleName("total0do90");
				totalBar.setValue(kolikoZnakov(skupniProcenti, 100));
				totalProcent.setValue(df.format(skupniProcenti) + "%");
			}
		
			for (int i = 0; i < velikostJsonFajla; i++) {
				barProcentLabels[i]
 = null;
				barImeLabels[i]
 = null;
				barGrafLabels[i]
 = null;
				stringiZaUredit[i]
 = null;
				stringiZaPrimerjat[i]
 = null;
			}
			jsonUrl = null;
			jsonOpenStream = null;
			jsonTxt = null;
			jsonUrlConnection = null;
			json = null;
			vrednosti = null;
			elementek = null;
			barImeLabels = null;
			barGrafLabels = null;
			barProcentLabels = null;
			stringiZaUredit = null;
			stringiZaPrimerjat = null;
			vrstniRed = null;
		} catch (MalformedURLException e) {
			if (layout.getComponentIndex(gl) != -1) {
				layout.removeComponent(gl);
				gl.detach();
			}
			if (layout.getComponentIndex(opozorilo) == -1) {
				layout.addComponent(opozorilo);
				opozorilo.detach();
			}
			logger.info("MalformedURLException while parsing JSON.");
			logger.error(e.getClass() + ": " +  e.getMessage(), e);
			logger.error(e.getStackTrace());
		} catch (IOException e) {
			if (layout.getComponentIndex(gl) != -1) {
				layout.removeComponent(gl);
				gl.detach();
			}
			if (layout.getComponentIndex(opozorilo) == -1) {
				layout.addComponent(opozorilo);
				opozorilo.detach();
			}
			logger.info("IOException while parsing JSON.");
			logger.error(e.getClass() + ": " +  e.getMessage(), e);
			logger.error(e.getStackTrace());
		} catch (IllegalStateException e) {
			if (layout.getComponentIndex(gl) != -1) {
				layout.removeComponent(gl);
				gl.detach();
			}
			if (layout.getComponentIndex(opozorilo) == -1) {
				layout.addComponent(opozorilo);
				opozorilo.detach();
			}
			logger.info("IllegalStateException while parsing XML.");
			logger.error(e.getClass() + ": " +  e.getMessage(), e);
			logger.error(e.getStackTrace());
		} catch (Error e) {
			if (layout.getComponentIndex(gl) != -1) {
				layout.removeComponent(gl);
				gl.detach();
			}
			if (layout.getComponentIndex(opozorilo) == -1) {
				layout.addComponent(opozorilo);
				opozorilo.detach();
			}
			logger.info("Error while parsing JSON");
			logger.error(e.getClass() + ": " +  e.getMessage(), e);
			logger.error(e.getStackTrace());
		}
    }

I can write comments in the code, translate the names of my variables or post other parts of my code if it would help.
Thank you very much.

Hello again.

I updated to Vaadin 7.0.2 and refresher 1.2.1.7. I wrote a new application. Just for fun I added Vaadin Charts 1.0.0. In my app I update the chart values every 10 seconds and every time the memory used my browser (chrome or firefox) increases. After a few hours all the memory is used unless I invalidate the session and set the refresh interval to 0.

[code]

public class NovivadindirektchartUI extends UI implements PortletListener, Refresher.RefreshListener {

final Refresher refresher = new Refresher();

protected void init(VaadinRequest request) {

    Random r = new Random();
    refresher.setRefreshInterval(10);
    refresher.addListener(this);
    refresher.setRefreshInterval(10);
    addExtension(refresher);
    Draw();

}

private void Draw() {
     
    final Configuration conf = new Configuration();
    
    conf.getChart().setType(ChartType.BAR);
    
    conf.setTitle(imeGrafa);
    
    x = new XAxis();
    x.setCategories(imenaNaXOsi);
    x.setTitle((String) null);
    conf.addxAxis(x);

    YAxis y = new YAxis();
    y.setMin(0);
    y.setMax(100);
    Title title = new Title("Zasedenost (procenti)");
    title.setVerticalAlign(VerticalAlign.HIGH);
    y.setTitle(title);
    conf.addyAxis(y);

    Tooltip tooltip = new Tooltip();
    tooltip.setFormatter("this.x +': '+ this.y +' procentov'");
    conf.setTooltip(tooltip);

    plot = new PlotOptionsBar();
    plot.setDataLabels(new Labels(true));
    conf.setPlotOptions(plot);

    Legend legend = new Legend();
    legend.setLayout(LayoutDirection.VERTICAL);
    legend.setHorizontalAlign(HorizontalAlign.RIGHT);
    legend.setVerticalAlign(VerticalAlign.BOTTOM);

    legend.setX(-50);
    legend.setY(-50);
    legend.setFloating(true);
    legend.setBorderWidth(1);
    legend.setBackgroundColor("#FFFFFF");
    legend.setShadow(true);
    conf.setLegend(legend);

    conf.disableCredits();
    List1.setName(imeGrafa);
    List1.setData(povprečneVrednosti);
	    
    if(series.isEmpty() == true) {
        series.add(List1);
    }
	
    conf.setSeries(series);
    chart.drawChart(conf);
    
    layout.addComponent(chart);

}

private void Update() {

    List1.updatePoint(0, r.nextInt(100));
    List1.updatePoint(1, r.nextInt(100));
    List1.updatePoint(2, r.nextInt(100));
    List1.updatePoint(3, r.nextInt(100));
    List1.updatePoint(4, r.nextInt(100));

}

public void refresh(Refresher source) {

    Update();

}

[/code]Does anyone else have the same problem. The application is running on Liferay portal 6.1.1.
I didn’t attach all the code just the important parts.

Thank you for your help.

I wonder if this is some portlet specific problem or also concerns other environments.

If you can create a minimal program that allows reproducing this (ideally as a servlet if this also occurs in servlets), please
create a ticket
with the complete test application source code and information about the versions used.