I suggested in the get-google-api Overview, I'm following up here with an issue created.
Platform information: OS X 10.9, Chrome 31.0.1650.57, GWT 2.5.1. Unknown if this problem exists on other platforms. After adding a PieChart to a widget (for example, a VerticalPanel) and then removing the PieChart (using HasWidgets.remove(widget), the PieChart no longer appears within the enclosing widget as expected. However, when I check Chrome Dev Tools Containment view, I can see that elements for the PieChart remain behind in a detached DOM tree, instead of being garbage collected. I followed up<https://groups.google.com/forum/#%21topic/Google-Web-Toolkit/HcbLxVn1M6Q>with the GWT group first. The only responder suggested that this DOM leak is entirely within the core visualization code, and not specific to GWT. Read the post for details on how we arrived at this conclusion. I've attached a stand-alone class that demonstrates the issue. To reproduce: 1. Deploy app in Prod mode 2. Open the app in Chrome 3. Click the "Add Chart" button and wait for chart to appear 4. Click the "Remove Chart: button 5. Using Chrome's dev tools, take a heap snapshot 6. Open the heap snapshot in the Containment view. You should see elements in the detached DOM tree, similar to the screenshot: <https://lh3.googleusercontent.com/-sVRJt4cmMdk/Up9-TH7Lr3I/AAAAAAAAABY/ZSnF3B9Y53U/s1600/Screen+Shot+2013-12-04+at+11.04.40+AM.png> Although the names for the detached element objects (or the references to them) are obscured, even when compiled PRETTY or DETAILED, a look inside them reveals that they are related to gwt-viz. Am I not removing the PieChart correctly, or is there a DOM/memory leak here? -- http://groups.google.com/group/Google-Web-Toolkit-Contributors --- You received this message because you are subscribed to the Google Groups "GWT Contributors" group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.
package demo.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.visualization.client.AbstractDataTable; import com.google.gwt.visualization.client.DataTable; import com.google.gwt.visualization.client.VisualizationUtils; import com.google.gwt.visualization.client.AbstractDataTable.ColumnType; import com.google.gwt.visualization.client.visualizations.corechart.Options; import com.google.gwt.visualization.client.visualizations.corechart.PieChart; //import com.smartgwt.client.widgets.calendar.Timeline; /** * This is a demo of how to properly handle dynamically created and destroyed * widgets. Entry point classes define <code>onModuleLoad()</code>. */ public class WidgetAddDelete implements EntryPoint { private final Button addChartButton = new Button("Add PieChart"); private final Button removeChartButton = new Button("Remove PieChart"); // private final Button addTimelineButton = new Button("Add Timeline"); // private final Button removeTimelineButton = new Button("Remove Timeline"); private final VerticalPanel mainPanel = new VerticalPanel(); private Widget contentWidget = null; // private Widget timelineWidget = null; /** * This is the entry point method. */ public void onModuleLoad() { mainPanel.add(addChartButton); mainPanel.add(removeChartButton); // mainPanel.add(addTimelineButton); // mainPanel.add(removeTimelineButton); RootPanel.get().add(mainPanel); setUpButtons(); } /** * Add click handlers to the buttons. */ private void setUpButtons() { addChartButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { if (contentWidget == null) { Runnable onLoadCallback = new Runnable() { public void run() { PieChart content = new PieChart(createTable(), createOptions()); mainPanel.add(content); contentWidget = content; } }; VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE); } } }); removeChartButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { if (contentWidget != null) { mainPanel.remove(contentWidget); contentWidget = null; } } }); // addTimelineButton.addClickHandler(new ClickHandler() { // public void onClick(final ClickEvent event) { // if (timelineWidget == null) { // Timeline timeline = new Timeline(); // mainPanel.add(timeline); // timelineWidget = timeline; // } // } // }); // removeTimelineButton.addClickHandler(new ClickHandler() { // public void onClick(final ClickEvent event) { // if (timelineWidget != null) { // timelineWidget.removeFromParent(); // mainPanel.remove(timelineWidget); // timelineWidget = null; // } // } // }); } private AbstractDataTable createTable() { DataTable data = DataTable.create(); data.addColumn(ColumnType.STRING, "Task"); data.addColumn(ColumnType.NUMBER, "Hours per Day"); data.addRows(2); data.setValue(0, 0, "Work"); data.setValue(0, 1, 14); data.setValue(1, 0, "Sleep"); data.setValue(1, 1, 10); return data; } private Options createOptions() { Options options = Options.create(); options.setWidth(400); options.setHeight(240); options.setTitle("My Daily Activities"); return options; } }