Community
Participate
Working Groups
To reproduce, run the following snippet (with VM arguments "") and observe growing memory consumption: public class TestTreeLeak { public static void main(String[] args) { Display display = new Display(); final Image image = display.getSystemImage(SWT.ICON_INFORMATION); Shell shell = new Shell(display); shell.setText("Test Tree leak based on SWT example: Images on the right side of the TreeItem"); shell.setLayout(new FillLayout()); Tree tree = new Tree(shell, SWT.MULTI | SWT.FULL_SELECTION); tree.setHeaderVisible(true); tree.setLinesVisible(true); int columnCount = 4; for (int i = 0; i < columnCount; i++) { TreeColumn column = new TreeColumn(tree, SWT.NONE); column.setText("Column " + i); } List<TreeItem> items = new ArrayList<>(); int itemCount = 3; for (int i = 0; i < itemCount; i++) { TreeItem item1 = new TreeItem(tree, SWT.NONE); item1.setText("item " + i); for (int c = 1; c < columnCount; c++) { item1.setText(c, "item [" + i + "-" + c + "]"); } items.add(item1); for (int j = 0; j < itemCount; j++) { TreeItem item2 = new TreeItem(item1, SWT.NONE); item2.setText("item [" + i + " " + j + "]"); for (int c = 1; c < columnCount; c++) { item2.setText(c, "item [" + i + " " + j + "-" + c + "]"); } items.add(item2); for (int k = 0; k < itemCount; k++) { TreeItem item3 = new TreeItem(item2, SWT.NONE); item3.setText("item [" + i + " " + j + " " + k + "]"); for (int c = 1; c < columnCount; c++) { item3.setText(c, "item [" + i + " " + j + " " + k + "-" + c + "]"); } items.add(item3); } } } /* * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly. * Therefore, it is critical for performance that these methods be as * efficient as possible. */ Listener paintListener = new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.MeasureItem: { Rectangle rect = image.getBounds(); event.width += rect.width; event.height = Math.max(event.height, rect.height + 2); break; } case SWT.PaintItem: { int x = event.x + event.width; Rectangle rect = image.getBounds(); int offset = Math.max(0, (event.height - rect.height) / 2); event.gc.drawImage(image, x, event.y + offset); break; } } } }; tree.addListener(SWT.MeasureItem, paintListener); tree.addListener(SWT.PaintItem, paintListener); for (int i = 0; i < columnCount; i++) { tree.getColumn(i).pack(); } shell.setSize(500, 200); shell.open(); AtomicBoolean b = new AtomicBoolean(true); AtomicInteger i = new AtomicInteger(0); Thread t = new Thread(new Runnable() { @Override public void run() { while (b.get()) { if (!display.isDisposed()) { display.asyncExec(new Runnable() { @Override public void run() { if (!display.isDisposed()) { int index = i.getAndIncrement(); TreeItem i0 = items.get((index + 0) % items.size()); tree.deselect(i0); TreeItem i1 = items.get((index + 1) % items.size()); tree.select(i1); } } }); } try { Thread.sleep(50); } catch (InterruptedException e) { } } } }); t.start(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } b.set(false); if (image != null) image.dispose(); display.dispose(); } } (essentially this snippet, changed to continually select elements in the tree, which causes the memory leak: http://www.java2s.com/Tutorial/Java/0280__SWT/AddIcontoTreeItem.htm) valgrind reports the memory leak e.g. as: ==94589== 12,540 (10,032 direct, 2,508 indirect) bytes in 627 blocks are definitely lost in loss record 302 of 14,499 ==94589== at 0x4C2B017: malloc (vg_replace_malloc.c:380) ==94589== by 0x2A31F68D: g_malloc (in /usr/lib64/libglib-2.0.so.0.5600.1) ==94589== by 0x2A336C8D: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.5600.1) ==94589== by 0x26F7696D: gtk_tree_path_new (gtktreemodel.c:594) ==94589== by 0x26F8733C: gtk_tree_store_get_path (gtktreestore.c:600) ==94589== by 0x269E652A: Java_org_eclipse_swt_internal_gtk_GTK_gtk_1tree_1model_1get_1path (in /home/sandreev/git/eclipse/eclipse.platform.swt.binaries/bundles/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4944r26.so) ==94589== by 0x18FABB88: ??? ==94589== by 0x11BF802B: ??? ==94589== by 0x66FE052: JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*) (in /usr/lib/jvm/java-11-openjdk-11.0.11.0.9-1.el7_9.x86_64/lib/server/libjvm.so) ==94589== by 0x676910C: jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*) [clone .isra.165] (in /usr/lib/jvm/java-11-openjdk-11.0.11.0.9-1.el7_9.x86_64/lib/server/libjvm.so) ==94589== by 0x6773EFB: jni_CallStaticLongMethodV (in /usr/lib/jvm/java-11-openjdk-11.0.11.0.9-1.el7_9.x86_64/lib/server/libjvm.so) ==94589== by 0x26743376: callback (in /home/sandreev/git/eclipse/eclipse.platform.swt.binaries/bundles/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4944r26.so) ==94589== by 0x2674F15A: fn1_6 (in /home/sandreev/git/eclipse/eclipse.platform.swt.binaries/bundles/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4944r26.so) ==94589== by 0x26D79E1A: gtk_cell_renderer_render (gtkcellrenderer.c:826) ==94589== by 0x26D703D1: render_cell (gtkcellarea.c:1147) ==94589== by 0x26D72E7F: gtk_cell_area_box_foreach_alloc (gtkcellareabox.c:1291) ==94589== by 0x26D6FF2A: gtk_cell_area_real_render (gtkcellarea.c:1189) ==94589== by 0x26FA9949: _gtk_tree_view_column_cell_render (gtktreeviewcolumn.c:2909) ==94589== by 0x26FA0A8B: gtk_tree_view_bin_draw (gtktreeview.c:5327) ==94589== by 0x26FA15FC: draw_bin (gtktreeview.c:5608) ==94589== by 0x26EC2AAB: _gtk_pixel_cache_repaint (gtkpixelcache.c:357) ==94589== by 0x26EC2AAB: _gtk_pixel_cache_draw (gtkpixelcache.c:447) ==94589== by 0x26F8CF27: gtk_tree_view_draw (gtktreeview.c:5651) ==94589== by 0x26E66D24: _gtk_marshal_BOOLEAN__BOXED (gtkmarshalers.c:83) ==94589== by 0x26FAF8FE: gtk_widget_draw_marshaller (gtkwidget.c:945) ==94589== by 0x2A08D901: g_closure_invoke (in /usr/lib64/libgobject-2.0.so.0.5600.1) ==94589== by 0x2A09FE1A: ??? (in /usr/lib64/libgobject-2.0.so.0.5600.1) ==94589== by 0x2A0A7CDB: g_signal_emit_valist (in /usr/lib64/libgobject-2.0.so.0.5600.1) ==94589== by 0x2A0A82DE: g_signal_emit (in /usr/lib64/libgobject-2.0.so.0.5600.1) ==94589== by 0x26FBA7F9: gtk_widget_draw_internal (gtkwidget.c:7025) ==94589== by 0x26D9FFD3: gtk_container_propagate_draw (gtkcontainer.c:3841) The problem seems to be in this code: // Account for the expander arrow offset in x position if (GTK.gtk_tree_view_get_expander_column (handle) == columnHandle) { /* indent */ GdkRectangle rect3 = new GdkRectangle (); GTK.gtk_widget_realize (handle); path = GTK.gtk_tree_model_get_path (modelHandle, iter); GTK.gtk_tree_view_get_cell_area (handle, path, columnHandle, rect3); contentX[0] += rect3.x; } Adding a call "GTK.gtk_tree_path_free (path)" fixes the leak.
New Gerrit change created: https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/180664
Seems like a regression from bug 531882, commit: https://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=90b11d0439eaf39696ee5c80da07e42a77c9ce34
Gerrit change https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/180664 was merged to [master]. Commit: http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=37a6acbe143086ed88de37657e1a7ee4dda113b2