Bug 354658 - 'History' does not dispose created PageSite instances when it is closed
Summary: 'History' does not dispose created PageSite instances when it is closed
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Team (show other bugs)
Version: 3.7   Edit
Hardware: All All
: P3 critical (vote)
Target Milestone: 3.8 M4   Edit
Assignee: Tomasz Zarna CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
: 331181 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-08-12 14:14 EDT by Remy Suen CLA
Modified: 2011-12-01 05:45 EST (History)
11 users (show)

See Also:


Attachments
Screenshot depicting the state in question. (70.08 KB, image/png)
2011-08-12 15:06 EDT, Remy Suen CLA
no flags Details
Screenshot depicting the state in question. (61.62 KB, image/png)
2011-08-12 19:07 EDT, Remy Suen CLA
no flags Details
The right fix v01 (32.17 KB, patch)
2011-10-19 10:35 EDT, Tomasz Zarna CLA
no flags Details | Diff
mylyn/context/zip (112.28 KB, application/octet-stream)
2011-10-19 10:35 EDT, Tomasz Zarna CLA
no flags Details
Fix v02 (36.78 KB, patch)
2011-11-03 08:33 EDT, Tomasz Zarna CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Remy Suen CLA 2011-08-12 14:14:20 EDT
When you show the history of some file in CVS, you will see a PageSite instance get instantiated. Place a breakpoint in PageSite's dispose() method and also GenericHistoryView's dispose() method. Close the 'History' view. Only the GHV's dispose() method will get called, the PageSite's one doesn't. :(

See also bug 331181 which is another problem related to PageSites and the GHV.
Comment 1 Remy Suen CLA 2011-08-12 15:06:15 EDT
Created attachment 201422 [details]
Screenshot depicting the state in question.

We dispose our 4.x PopupMenuExtender when the PageSite gets disposed but since the site never gets disposed in a GHV, the PME doesn't get destroyed and we end up causing a large leak comprising of EGit-related objects.
Comment 2 Remy Suen CLA 2011-08-12 16:22:59 EDT
Looking at the code again, it's not clear how Team can resolve this problem (without too much churn). This is because the dispose() method of PageSite is a protected method. PageBookView can call this method because the PBV is in the same package as PageSite (org.eclipse.ui.part). Perhaps PageSite itself shouldn't have been a public API, as this would "force" PBV look-alikes (such as the GenericHistoryView) to extend PBV instead of implementing it themselves (like what the GHV does, it actually extends ViewPart and not PBV).

I suppose Team could make GHV subclass PBV instead but I imagine it will have to undergo a bit of testing even if the code changes aren't _huge_.
Comment 3 Remy Suen CLA 2011-08-12 16:34:14 EDT
DJ, I know you've had memory problems with EGit. Were you using 3.x or 4.x? Or have you noticed the problem on both? I haven't analyzed the issue on 3.x yet so I don't know if the same problem occurs there or not.
Comment 4 Remy Suen CLA 2011-08-12 19:07:43 EDT
Created attachment 201449 [details]
Screenshot depicting the state in question.

I don't think the first screenshot I provided in comment 1 was that good, I think I might have screwed it up.

This new one is better and is from 3.x and not 4.x. If PageSite's dispose() method was called then its tool bar manager would've cleared its cache but this has not happened.
Comment 5 Remy Suen CLA 2011-08-13 06:33:35 EDT
For CVS, it seems that the context menu is registered with the view's site so this does not become a problem.

Thread [main] (Suspended (breakpoint at line 122 in PopupMenuExtender))	
	PopupMenuExtender.<init>(String, MenuManager, ISelectionProvider, IWorkbenchPart, boolean) line: 122	
	PartSite.registerContextMenu(String, MenuManager, ISelectionProvider, boolean, IWorkbenchPart, Collection) line: 113	
	ViewSite(PartSite).registerContextMenu(String, MenuManager, ISelectionProvider) line: 354	
	ViewSite(PartSite).registerContextMenu(MenuManager, ISelectionProvider) line: 363	
	CVSHistoryPage.contributeActions() line: 767	
	CVSHistoryPage.createControl(Composite) line: 255	
	GenericHistoryView.createPage(IHistoryPageSource, Object) line: 857	
	GenericHistoryView.showHistoryPageFor(Object, boolean, boolean, IHistoryPageSource) line: 727	
	TeamUI.showInputInView(IWorkbenchPage, Object, IHistoryView, IHistoryPageSource) line: 129	
	TeamUI.showHistoryFor(IWorkbenchPage, Object, IHistoryPageSource) line: 110	
	ShowHistoryAction$1.run(IProgressMonitor) line: 66	
	RepositoryManager.run(IRunnableWithProgress, IProgressMonitor) line: 717	
	CVSAction$2.run(IProgressMonitor) line: 360	
	CVSAction$3.run() line: 369	
	BusyIndicator.showWhile(Display, Runnable) line: 70	
	ShowHistoryAction(CVSAction).run(IRunnableWithProgress, boolean, int) line: 366	
	ShowHistoryAction.execute(IAction) line: 63	
	ShowHistoryAction(CVSAction).run(IAction) line: 117	
	ShowHistoryAction(TeamAction).runWithEvent(IAction, Event) line: 549	
	ObjectPluginAction(PluginAction).runWithEvent(Event) line: 241
Comment 6 DJ Houghton CLA 2011-08-15 09:15:51 EDT
In general I've been using 4.x builds.
Comment 7 Remy Suen CLA 2011-08-27 07:36:04 EDT
(In reply to comment #2)
> Looking at the code again, it's not clear how Team can resolve this problem
> (without too much churn). This is because the dispose() method of PageSite is a
> protected method.

Well, I guess they could just extend PageSite and "expose" that dispose() method so it could be called.
Comment 8 Remy Suen CLA 2011-09-22 11:11:36 EDT
DJ had some memory problems and from inspecting his heap dump, he has about 70 megs leaking because of this bug.

Either we workaround the problem in EGit using the same code as the CVS plug-in or the code needs to be fixed in Team.
Comment 9 DJ Houghton CLA 2011-09-22 11:13:22 EDT
Adding Dani to the CC list (as a PMC rep) as I'm not sure who is working on Team now.
Comment 10 Dani Megert CLA 2011-09-22 11:18:06 EDT
Szymon, can you take a look?
Comment 11 Tomasz Zarna CLA 2011-09-30 08:17:08 EDT
Remy, in 3.x (in I20110927-0800 to be more precise) when I close the History view GHV#dispose() is not called. It only happens when I'm closing the workbench. Did you refer to org.eclipse.team.ui.history.HistoryPage being disposed when switching editors or changing selection. A lame question for a UI guy: are these PageSite instances expected to be disposed at the same time as HistoryPages? From a quick look at PageBookView it seems that PageSites are disposed when disposing the view.

As for the solution you suggested: GHV looks like a perfect candidate to be a subclass of PBV, I wonder why it was decided to extend ViewPart directly. Anyway, I would be fine with trying that now for any other view but the History ;) Nevertheless I think I will give it a try as see how much effort it requires.
Comment 12 Remy Suen CLA 2011-09-30 08:47:12 EDT
(In reply to comment #11)
> Remy, in 3.x (in I20110927-0800 to be more precise) when I close the History
> view GHV#dispose() is not called. It only happens when I'm closing the
> workbench.

I tested this with I20110927-0800 on Windows XP and GHV's dispose() method _is_ getting invoked.

Thread [main] (Suspended (breakpoint at line 906 in GenericHistoryView))	
	GenericHistoryView.dispose() line: 906	
	ViewReference(WorkbenchPartReference).doDisposePart() line: 737	
	ViewReference.doDisposePart() line: 104	
	ViewReference(WorkbenchPartReference).dispose() line: 684	
	WorkbenchPage.disposePart(WorkbenchPartReference) line: 1797	
	WorkbenchPage.partRemoved(WorkbenchPartReference) line: 1789	
	ViewFactory.releaseView(IViewReference) line: 257	
	Perspective.hideView(IViewReference) line: 606	
	WorkbenchPage.hideView(IViewReference) line: 2469	
	ViewPane.doHide() line: 224	
	ViewStack(PartStack).close(IPresentablePart) line: 537	
	ViewStack(PartStack).close(IPresentablePart[]) line: 520	
	PartStack$1.close(IPresentablePart[]) line: 120	
	TabbedStackPresentation$1.handleEvent(TabFolderEvent) line: 83	
	DefaultTabFolder(AbstractTabFolder).fireEvent(TabFolderEvent) line: 269	
	DefaultTabFolder(AbstractTabFolder).fireEvent(int, AbstractTabItem) line: 278	
	DefaultTabFolder.access$1(DefaultTabFolder, int, AbstractTabItem) line: 1	
	DefaultTabFolder$1.closeButtonPressed(CTabItem) line: 71	
	PaneFolder.notifyCloseListeners(CTabItem) line: 631	
	PaneFolder$3.close(CTabFolderEvent) line: 206	
	CTabFolder.onMouse(Event) line: 1598

Please ensure you do _not_ have any other 'History' views open in other perspectives when you are testing this. If you also have the view in the other perspective, then the view is still "alive".

Note that if IWorkbenchPart's dispose() method was only called when the workbench shutdown, we would be having major leaking issues. :)

> A lame question for a UI
> guy: are these PageSite instances expected to be disposed at the same time as
> HistoryPages?

You're right, the page and the page site should be destroyed. Though the page site should be disposed _after_ the page is destroyed. You can take a look at PageBookView's removePage(PageRec) method.

> From a quick look at PageBookView it seems that PageSites are
> disposed when disposing the view.

This is one of the scenarios, yes. We also destroy pages if the "target" part in question is destroyed. See PageBookView's partClosed(IWorkbenchPart) method. For example, the 'Outline' view has a page in the current Java editor. However, if that Java editor is closed, the page in the 'Outline' view also gets disposed even though the 'Outline' view itself has not been closed.
Comment 13 Tomasz Zarna CLA 2011-09-30 09:14:09 EDT
(In reply to comment #12)
> Please ensure you do _not_ have any other 'History' views open in other
> perspectives when you are testing this.

Got it now, thx.
Comment 14 Tomasz Zarna CLA 2011-10-03 05:35:39 EDT
(In reply to comment #8)
> Either we workaround the problem in EGit using the same code as the CVS plug-in
> or the code needs to be fixed in Team.

Remy, have you looked at how a potential workaround in EGit could look like? The fix in Team is not going to be trivial, so I thought we could fix it in EGit first (to avoid the leak and reduce severity). This would bought me some time to provide a proper fix in Team later on (after 3.8 M3).
Comment 15 Remy Suen CLA 2011-10-03 07:59:21 EDT
(In reply to comment #14)
> Remy, have you looked at how a potential workaround in EGit could look like?

No. On the surface it seems like it'd just be a matter of changing the context menu registration to use the view's site instead of the page's site but I haven't actually even launched an inner with that change before to be honest.
Comment 16 Remy Suen CLA 2011-10-04 18:55:21 EDT
I can confirm that changing the code to use the view's site instead of the page's site does cause GitHistoryPage, FindToolbar, and SWTCommit objects to have their finalize() methods called.
Comment 17 Tomasz Zarna CLA 2011-10-11 10:47:57 EDT
Remy, any chance to release the workaround to EGit, so we can lower the severity here?
Comment 18 Remy Suen CLA 2011-10-11 10:58:35 EDT
(In reply to comment #17)
> Remy, any chance to release the workaround to EGit, so we can lower the
> severity here?

It's hard to say because I don't know what adverse effects creating the context menu off of the part's site might have. Perhaps it's safe since the CVS plug-in does it this way but I can't be sure.

Another workaround might be to just null out the references manually so that the commit objects get garbage collected.
Comment 19 Remy Suen CLA 2011-10-11 11:13:48 EDT
(In reply to comment #17)
> Remy, any chance to release the workaround to EGit, so we can lower the
> severity here?

I've emailed egit-dev asking for input from the community.

As to the severity, well, it doesn't really matter to me at the end of the day. One man's bug is another man's enhancement request as I like to say. ;)

This bug usually doesn't affect me on a day-to-day basis and I usually just restart Eclipse if it gets out of hand. I have a very high tolerance and I know you all are working hard to find the _right_ fix for this problem. :)
Comment 20 Tomasz Zarna CLA 2011-10-19 10:35:50 EDT
Created attachment 205535 [details]
The right fix v01

Here is a first attempt to make GHV a sublclass of PageBookView. I've tested it briefly and it seems to be working fine, it even fixes the bug :) Any chance to move it to early 3.8 M4 so I get extra 2 weeks to check if the new GHV is as good as the old one? 

Remy, Dani, is that ok with you guys? If I had prepared the fix a week earlier, I wouldn't ask you about it, but it's only a week before M3 and I'm not 100% about the patch.
Comment 21 Tomasz Zarna CLA 2011-10-19 10:35:57 EDT
Created attachment 205537 [details]
mylyn/context/zip
Comment 22 Remy Suen CLA 2011-10-19 11:54:03 EDT
(In reply to comment #20)
> Created attachment 205535 [details]
> The right fix v01

I didn't go over the whole patch but I am a little sketchy about your private implementation of IWorkbenchPart which you call super.partActivated(*) with. I also see that you have a TODO comment there. :P

> Here is a first attempt to make GHV a sublclass of PageBookView. I've tested it
> briefly and it seems to be working fine, it even fixes the bug :)

I can confirm that PageSites are now disposed and that the change to make GHV extend PBV also fixes bug 331181! :)

> Any chance to
> move it to early 3.8 M4 so I get extra 2 weeks to check if the new GHV is as
> good as the old one? 

I am okay with delaying this to M4. While it is a major problem, the low number of people that are CC'd on this bug leads me to believe that users of EGit are either a) not working with repositories with a long list of commits or are b) filtering their list of commits in the preferences.

Since the 'History' view is an integral part of all of our daily development, I don't think we should release this until we are confident about it.
Comment 23 Dani Megert CLA 2011-10-19 12:24:11 EDT
(In reply to comment #22)
> (In reply to comment #20)
> > Created attachment 205535 [details] [diff] [details]
> > The right fix v01
> 
> I didn't go over the whole patch but I am a little sketchy about your private
> implementation of IWorkbenchPart which you call super.partActivated(*) with. I
> also see that you have a TODO comment there. :P

This definitely sounds like M4 to me ;-)
Comment 24 Tomasz Zarna CLA 2011-10-24 07:06:51 EDT
(In reply to comment #22)
> I didn't go over the whole patch but I am a little sketchy about your private
> implementation of IWorkbenchPart which you call super.partActivated(*) with. 

That was not my idea, I noticed this kind of fake parts being used by other PageBookView subclasses: SynchronizeViewWorkbenchPart in SynchronizeView, ConsoleWorkbenchPart in ConsoleView and last but not least DummyPart in SearchView :) I do agree calling super.partActivated(*) smells fishy, I did plan to look at it again.

> I also see that you have a TODO comment there. :P

Yup, I still need to figure out how to preserve behavior of the old GHV where a new page is *not* created for a file (input) with the same HistoryPageSource. In the "fix v01" a new page is created each time.
Comment 25 Tomasz Zarna CLA 2011-11-03 08:33:38 EDT
Created attachment 206402 [details]
Fix v02

(In reply to comment #24)
> calling super.partActivated(*) smells fishy, I did plan to look at it again.

This works just fine, #partActivated is overridden in GHV so it doesn't call super.partActivated(IWorkbenchPart), it's done in #showHistoryPageFor(...). It may be confusing at first sight, but it looks like a pattern for GHV subclasses which have public methods for displaying a page eg. Console#display(IConsole), SynchronizeView#display(ISynchronizeParticipant) and GHV#showHistoryPageFor(...).

> need to figure out how to preserve behavior of the old GHV where a
> new page is *not* created for a file (input) with the same HistoryPageSource.

This has been acheived by implementing #equals in HistoryPageSourceWorkbenchPart and overriding #getPageRec in GHV.

I will double check if making the GHV a PBV actually fixes the bug, then I will do some smoke testing and call GHV#showHistoryPageFor(...) with different configurations (pinned, linked with editor etc) and providers (CVS, SVN, git). If I don't find anything suspicious I will release the fix this week (on Monday at the latest).
Comment 26 Tomasz Zarna CLA 2011-11-03 09:16:40 EDT
(In reply to comment #25)
> Created attachment 206402 [details]
> Fix v02

Forgot to remove the TODO comment from the patch. It's no longer valid.
Comment 27 Tomasz Zarna CLA 2011-11-03 11:35:21 EDT
Fixed with 8bd7229015f8e34a5c3e23ca9b86504023141b51. Available in builds >=N20111103-2000.
Comment 28 Tomasz Zarna CLA 2011-12-01 05:45:38 EST
*** Bug 331181 has been marked as a duplicate of this bug. ***