Bug 126442 - [Viewers] each compare editor is leaked
Summary: [Viewers] each compare editor is leaked
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Compare (show other bugs)
Version: 3.2   Edit
Hardware: PC Windows XP
: P1 major (vote)
Target Milestone: 3.3 M7   Edit
Assignee: Michael Valenta CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on:
Blocks:
 
Reported: 2006-02-03 20:21 EST by Darin Swanson CLA
Modified: 2007-04-05 10:48 EDT (History)
1 user (show)

See Also:


Attachments
Reference graph + alloc backtrace (10.99 KB, text/html)
2007-04-03 05:26 EDT, Dani Megert CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Darin Swanson CLA 2006-02-03 20:21:27 EST
I was profiling on I20060131-1200 and noticed leakage on opening and closing the Compare editor.

Test case:
In the Synchronize view, double click on an outgoing CVS change
Close the resulting Compare Editor.

Using OptimizeIt, I see leakage which appears to be traced back to the toolbar created in the CompareViewerPane not being disposed.

This likely be handled by disposing the toolbarmanager in the dispose listener?
Comment 1 Andre Weinand CLA 2006-02-06 04:52:45 EST
fixed for I20060207
Comment 2 Darin Swanson CLA 2006-02-14 17:06:25 EST
There appears to still be a problem here with Java file compares
The following stack shows a toolbar manager etc getting created on the dispose of the JavaStructureDiffViewer. This manager and toolbar do not get disposed.

	CompareEditorInput$3(CompareViewerPane).getToolBarManager() line: 146
	CompareViewerPane.getToolBarManager(Composite) line: 124
	JavaStructureDiffViewer.setSmartButtonVisible(boolean) line: 202
	JavaStructureDiffViewer.compareInputChanged(ICompareInput) line: 126
	JavaStructureDiffViewer(StructureDiffViewer).handleDispose(DisposeEvent) line: 163
	ContentViewer$2.widgetDisposed(DisposeEvent) line: 189
	TypedListener.handleEvent(Event) line: 101
	EventTable.sendEvent(Event) line: 66
	Tree(Widget).sendEvent(Event) line: 925
	Tree(Widget).sendEvent(int, Event, boolean) line: 949
	Tree(Widget).sendEvent(int) line: 930
	Tree(Widget).release(boolean) line: 740
	CompareEditorInput$3(Composite).releaseChildren(boolean) line: 623
	CompareEditorInput$3(Widget).release(boolean) line: 743
	Splitter(Composite).releaseChildren(boolean) line: 623
	Splitter(Widget).release(boolean) line: 743
	Splitter(Composite).releaseChildren(boolean) line: 623
	Splitter(Widget).release(boolean) line: 743
	Composite.releaseChildren(boolean) line: 623
	Composite(Widget).release(boolean) line: 743
	Composite.releaseChildren(boolean) line: 623
	Composite(Widget).release(boolean) line: 743
	Composite(Widget).dispose() line: 412
	EditorPane(PartPane).dispose() line: 164
	EditorReference(WorkbenchPartReference).dispose() line: 628
	WorkbenchPage.disposePart(WorkbenchPartReference) line: 1435
	WorkbenchPage.handleDeferredEvents() line: 1262
	WorkbenchPage.deferUpdates(boolean) line: 1246
	WorkbenchPage.closeEditors(IEditorReference[], boolean) line: 1220
	WorkbenchPage.closeEditor(IEditorReference, boolean) line: 1275
	EditorPane.doHide() line: 54
	EditorStack(PartStack).close(IPresentablePart) line: 497
	EditorStack.close(IPresentablePart[]) line: 201
	PartStack$1.close(IPresentablePart[]) line: 105
	TabbedStackPresentation$1.handleEvent(TabFolderEvent) line: 81
	DefaultTabFolder(AbstractTabFolder).fireEvent(TabFolderEvent) line: 267
	DefaultTabFolder(AbstractTabFolder).fireEvent(int, AbstractTabItem) line: 276
	DefaultTabFolder.access$1(DefaultTabFolder, int, AbstractTabItem) line: 1
	DefaultTabFolder$1.closeButtonPressed(CTabItem) line: 67
	PaneFolder.notifyCloseListeners(CTabItem) line: 580
	PaneFolder$3.close(CTabFolderEvent) line: 187
	CTabFolder.onMouse(Event) line: 2105
	CTabFolder$1.handleEvent(Event) line: 291
	EventTable.sendEvent(Event) line: 66
	CTabFolder(Widget).sendEvent(Event) line: 925
	Display.runDeferredEvents() line: 3287
	Display.readAndDispatch() line: 2907
	Workbench.runEventLoop(Window$IExceptionHandler, Display) line: 1899
	Workbench.runUI() line: 1863
	Workbench.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 417
	PlatformUI.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 143
	IDEApplication.run(Object) line: 106
	PlatformActivator$1.run(Object) line: 99
	EclipseAppLauncher.runApplication(Object) line: 92
	EclipseAppLauncher.start(Object) line: 68
	EclipseStarter.run(Object) line: 374
	EclipseStarter.run(String[], Runnable) line: 169
	NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
	NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
	DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
	Method.invoke(Object, Object[]) line: 324
	Main.invokeFramework(String[], URL[]) line: 338
	Main.basicRun(String[]) line: 282
	Main.run(String[]) line: 977
	Main.main(String[]) line: 952
Comment 3 Andre Weinand CLA 2006-02-16 04:07:55 EST
Not for M5
Comment 4 Dani Megert CLA 2007-04-03 05:24:46 EDT
Increasing priority since every single compare editor is leaked as long as its editor input is in the navigation history.
Comment 5 Dani Megert CLA 2007-04-03 05:26:05 EDT
Created attachment 62756 [details]
Reference graph + alloc backtrace
Comment 6 Michael Valenta CLA 2007-04-03 08:58:17 EDT
There appears to be 2 problems mentioned here:

1) Comment 2 indicates a leak occurs because a tool bar is recreated when the editor is closed. This is old so I'll need to confirm that it is still the case.

2) A change in 3.3 has caused the editor to be leaked because the editor history is holding onto the input which is holding onto the editor. I think the real issue here is that the editor history is keeping a reference to the editor input. Compare editors do not generally stay in the editor history when the are closed but there appears to be some scenarios where a reference is kept. If they are kept, an error occurs if the input is selected from the drop down. Regardless, in the very least, I will address the leak and will hopefully be able to sort of the reference in the editor history.
Comment 7 Dani Megert CLA 2007-04-03 09:05:52 EDT
>I think the
>real issue here is that the editor history is keeping a reference to the editor
>input.
Nope. This is well documents in IEditorInput:

 * Please note that it is important that the editor input be light weight.
 * Within the workbench, the navigation history tends to hold on to editor
 * inputs as a means of reconstructing the editor at a later time. The
 * navigation history can hold on to quite a few inputs (i.e., the default is
 * fifty). The actual data model should probably not be held in the input.
Comment 8 Michael Valenta CLA 2007-04-03 09:45:15 EDT
Thanks for the info. I have released a fix for 2 to HEAD and will investigate 1 during M7.
Comment 9 Dani Megert CLA 2007-04-04 04:10:03 EDT
I verified your fix in HEAD. There are two problems with it:

1. it give an NPE (see below)
2. the editor input is gone but there's still every last closed editor leaked because the editor contributor holds on to the last active editor.

!ENTRY org.eclipse.ui 4 0 2007-04-04 10:05:15.454
!MESSAGE Unhandled event loop exception
!STACK 0
java.lang.NullPointerException
	at org.eclipse.compare.CompareEditorInput.removeCompareInputChangeListener(CompareEditorInput.java:1023)
	at org.eclipse.compare.contentmergeviewer.ContentMergeViewer.handleDispose(ContentMergeViewer.java:909)
	at org.eclipse.compare.contentmergeviewer.TextMergeViewer.handleDispose(TextMergeViewer.java:1762)
	at org.eclipse.jface.viewers.ContentViewer$2.widgetDisposed(ContentViewer.java:191)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:116)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:938)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:962)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:943)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:740)
	at org.eclipse.swt.widgets.Composite.releaseChildren(Composite.java:662)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:743)
	at org.eclipse.swt.widgets.Composite.releaseChildren(Composite.java:662)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:743)
	at org.eclipse.swt.widgets.Composite.releaseChildren(Composite.java:662)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:743)
	at org.eclipse.swt.widgets.Composite.releaseChildren(Composite.java:662)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:743)
	at org.eclipse.swt.widgets.Composite.releaseChildren(Composite.java:662)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:743)
	at org.eclipse.swt.widgets.Widget.dispose(Widget.java:410)
	at org.eclipse.ui.internal.PartPane.dispose(PartPane.java:175)
	at org.eclipse.ui.internal.WorkbenchPartReference.dispose(WorkbenchPartReference.java:668)
	at org.eclipse.ui.internal.WorkbenchPage.disposePart(WorkbenchPage.java:1586)
	at org.eclipse.ui.internal.WorkbenchPage.handleDeferredEvents(WorkbenchPage.java:1345)
	at org.eclipse.ui.internal.WorkbenchPage.deferUpdates(WorkbenchPage.java:1329)
	at org.eclipse.ui.internal.WorkbenchPage.closeEditors(WorkbenchPage.java:1303)
	at org.eclipse.ui.internal.WorkbenchPage.closeEditor(WorkbenchPage.java:1358)
	at org.eclipse.ui.internal.EditorPane.doHide(EditorPane.java:61)
	at org.eclipse.ui.internal.PartStack.close(PartStack.java:519)
	at org.eclipse.ui.internal.EditorStack.close(EditorStack.java:209)
	at org.eclipse.ui.internal.PartStack$1.close(PartStack.java:119)
	at org.eclipse.ui.internal.presentations.util.TabbedStackPresentation$1.handleEvent(TabbedStackPresentation.java:81)
	at org.eclipse.ui.internal.presentations.util.AbstractTabFolder.fireEvent(AbstractTabFolder.java:267)
	at org.eclipse.ui.internal.presentations.util.AbstractTabFolder.fireEvent(AbstractTabFolder.java:276)
	at org.eclipse.ui.internal.presentations.defaultpresentation.DefaultTabFolder.access$1(DefaultTabFolder.java:1)
	at org.eclipse.ui.internal.presentations.defaultpresentation.DefaultTabFolder$1.closeButtonPressed(DefaultTabFolder.java:67)
	at org.eclipse.ui.internal.presentations.PaneFolder.notifyCloseListeners(PaneFolder.java:596)
	at org.eclipse.ui.internal.presentations.PaneFolder$3.close(PaneFolder.java:189)
	at org.eclipse.swt.custom.CTabFolder.onMouse(CTabFolder.java:2142)
	at org.eclipse.swt.custom.CTabFolder$1.handleEvent(CTabFolder.java:312)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:938)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3673)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3284)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2361)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2325)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2200)
	at org.eclipse.ui.internal.Workbench$4.run(Workbench.java:466)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:289)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:461)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:101)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:152)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:106)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:76)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:359)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:174)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:585)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:476)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:416)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1141)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1116)
Comment 10 Dani Megert CLA 2007-04-04 04:12:39 EDT
Michael, once you have fixed the NPE adding the following method to CompareEditorContributor will fix the remaining leakage:

	/*
	 * @see org.eclipse.ui.part.EditorActionBarContributor#dispose()
	 * @since 3.3
	 */
	public void dispose() {
		setActiveEditor(null);
		super.dispose();
	}

HTH
Dani
Comment 11 Michael Valenta CLA 2007-04-04 08:37:42 EDT
Thanks Dani. I have a question for you. Why is the workbench keeping a reference to a disposed IEditorActionBarContributor? The javadoc doesn't seem to indicate that a disposed instance can be reused so I don;t see why the reference would be kept.
Comment 12 Dani Megert CLA 2007-04-04 08:47:02 EDT
Because your contributor registers global action handlers in setActiveEditor(...) and they remain connected if you don't unregister them. I guess the reference to the contributor comes from there.
Comment 13 Michael Valenta CLA 2007-04-04 09:08:26 EDT
I see. I'm used to views where the SubActionBar handles that. I noticed that other editor contributors (e.g. BasicTextEditorActionContributor) clear the actions on dispose so I'll do that too.
Comment 14 Michael Valenta CLA 2007-04-04 10:46:47 EDT
I've released the fix for the NPE on Compare with Each Other and I've added the editor contribution dispose which nulls the editor and the global actions.
Comment 15 Dani Megert CLA 2007-04-04 12:29:01 EDT
Michael, I've verified the bug in HEAD.
Comment 16 Dani Megert CLA 2007-04-04 12:29:23 EDT
Of course I meant the fix not the bug. OK to close.
Comment 17 Michael Valenta CLA 2007-04-05 10:48:53 EDT
I have released a fix for the problem mentioned in comment 2 as well.