Bug 255120 - [MemoryView] RenderingViewPane "leaks" IMemoryBlockRetrieval references
Summary: [MemoryView] RenderingViewPane "leaks" IMemoryBlockRetrieval references
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.5 M6   Edit
Assignee: Natasha D'Silva CLA
QA Contact:
URL:
Whiteboard:
Keywords: contributed
Depends on:
Blocks:
 
Reported: 2008-11-12 18:32 EST by John Cortell CLA
Modified: 2010-02-09 15:40 EST (History)
2 users (show)

See Also:


Attachments
patch with a fix (14.50 KB, text/plain)
2009-02-19 14:35 EST, Natasha D'Silva CLA
no flags Details
updated patch (14.53 KB, patch)
2009-03-02 15:42 EST, Natasha D'Silva CLA
no flags Details | Diff
updated patch (9.73 KB, patch)
2009-03-05 16:35 EST, Samantha Chan CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description John Cortell CLA 2008-11-12 18:32:22 EST
RenderingViewPane has a hashtable called 'fTabFolderForDebugView'. While the memory view stays open, each successive debug launch adds a IMemoryBlockRetrieval instance to the table. The instance is not removed when the debug session terminates. This is a serious leak.

Sure, the table is cleared when the Memory View is closed, but that's not a reasonable cleanup policy. An end-user may do many successive debug sessions without ever closing the Memory view or leaving the Debug perspective. Needlessly keeping a IMemoryBlockRetrieval alive can be very expensive since quite a bit of memory can be tied to it. RenderingViewPane really needs to clean up the map on a IDebugTarget termination.

Reproducing this requires CDT and a few breakpoints:
1. Set breakpoints in RenderingViewPane.java and AbstractMemoryViewPane.java in all locations where fTabFolderForDebugView's put, remove and clear methods are called.
2. Launch runtime workbench
3. Switch to debug perspective.
4. Open the Memory view
5. Launch debug session. Note IMemoryBlockRetrieval isntance is added to the table.
6. Terminate debug session. Note the IMemoryBlockRetrieval instance is not removed from the table.

On every iteration of 5&6, the table keeps growing.
Comment 1 Samantha Chan CLA 2008-11-12 22:54:51 EST
Will investigate.  I do not think there is a good point to clean up the table because IMemoryBlockRetrieval is not really tied to a debug target / ITerminate.  We cannot listen for TERMINATE event and determine that the memory block retrieval can be removed.  
Comment 2 Samantha Chan CLA 2009-02-05 17:36:04 EST
Natasha, please investigate.
Comment 3 Natasha D'Silva CLA 2009-02-19 14:35:30 EST
Created attachment 126207 [details]
patch with a fix

This patch listens for a termination event from the IMemoryBlockRetrieval object and removes it from the map when this happens. It also uses the hashcode for the retrieval objects as the key into the map, rather than the object itself.
Comment 4 Samantha Chan CLA 2009-03-02 12:07:06 EST
Tested out the fix and found this error, when switching between debug sessions:

1)  I had two sessions that had renderings created
2)  I had 2 other sessions without any renderings
3)  Terminate the first two
4)  Now switch between the two remaining sessions and I got the following SWT exception.

Thread [main] (Suspended (exception SWTException))	
	owns: RunnableLock  (id=124)	
	SWT.error(int, Throwable, String) line: 3862	
	SWT.error(int, Throwable) line: 3775	
	SWT.error(int) line: 3746	
	CTabFolder(Widget).error(int) line: 463	
	CTabFolder(Widget).checkWidget() line: 336	
	CTabFolder.addSelectionListener(SelectionListener) line: 491	
	RenderingViewPane(AbstractMemoryViewPane).setTabFolder(CTabFolder) line: 196	
	RenderingViewPane(AbstractMemoryViewPane).emptyFolder() line: 250	
	RenderingViewPane.emptyFolder() line: 957	
	RenderingViewPane.handleDebugElementSelection(IMemoryViewTab, IAdaptable) line: 641	
	RenderingViewPane.access$12(RenderingViewPane, IMemoryViewTab, IAdaptable) line: 591	
	RenderingViewPane$8.runInUIThread(IProgressMonitor) line: 1183	
	UIJob$1.run() line: 95	
	RunnableLock.run() line: 35	
	UISynchronizer(Synchronizer).runAsyncMessages(boolean) line: 133	
	Display.runAsyncMessages(boolean) line: 3852	
	Display.readAndDispatch() line: 3473	
	Workbench.runEventLoop(Window$IExceptionHandler, Display) line: 2388	
	Workbench.runUI() line: 2352	
	Workbench.access$4(Workbench) line: 2204	
	Workbench$5.run() line: 499	
	Realm.runWithDefault(Realm, Runnable) line: 333	
	Workbench.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 492	
	PlatformUI.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 149	
	IDEApplication.start(IApplicationContext) line: 113	
	EclipseAppHandle.run(Object) line: 194	
	EclipseAppLauncher.runApplication(Object) line: 110	
	EclipseAppLauncher.start(Object) line: 79	
	EclipseStarter.run(Object) line: 368	
	EclipseStarter.run(String[], Runnable) line: 179	
	NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
	NativeMethodAccessorImpl.invoke(Object, Object[]) line: 45	
	DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 37	
	Method.invoke(Object, Object...) line: 599	
	Main.invokeFramework(String[], URL[]) line: 556	
	Main.basicRun(String[]) line: 511	
	Main.run(String[]) line: 1270	
	Main.main(String[]) line: 1246	
Comment 5 Samantha Chan CLA 2009-03-02 12:16:29 EST
The problem is in the AbstractMemoryViewPane#handleDebugEvents method.
The when a terminate event is received, we dispose the tab folder that is associated with the memory block retrieval. If the memory view is empty when the debug session is terminated, the tab folder gets disposed. Unfortunately, the empty tab folder is reused in the view, and should never been disposed.

Need to add code to check for the empty tab folder before disposing it.

Comment 6 Natasha D'Silva CLA 2009-03-02 15:42:27 EST
Created attachment 127222 [details]
updated patch
Comment 7 Samantha Chan CLA 2009-03-05 16:35:19 EST
Created attachment 127720 [details]
updated patch 

* moved #getHashCode to MemoryViewUtils
* code clean up
Comment 8 Samantha Chan CLA 2009-03-05 16:40:20 EST
Applied patch.
Comment 9 Samantha Chan CLA 2009-03-05 16:40:33 EST
Verified.
Comment 10 Curtis Windatt CLA 2009-03-05 17:33:39 EST
The committed fix had a compile error in it.  I replaced the method in MemoryViewUtils with the following

public static Integer getHashCode(Object o)
{
	return new Integer(o.hashCode());
}
Comment 11 Samantha Chan CLA 2009-03-05 17:47:15 EST
Curtis, sorry about that and thanks for fixing it.  Not sure why the error did not show up in my workspace.

I extracted the code and went back to the previous version, but still did not see an error.  What error did you get?  I am just curious and wondering if I have a bad workspace set up.
Comment 12 Curtis Windatt CLA 2009-03-06 10:24:56 EST
The method valueOf(String) in the type Integer is not applicable for the arguments (int)	MemoryViewUtil.java	org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory	line 263	Java Problem

Integer.valueOf(int) was added in 1.5. 

Do you have a 1.4.2 JRE in your workspace?  If not Eclipse can't figure out that the code you are using is 1.5 only.  API Tooling just added some additional support for this, so you just need a fragment installed not a full JRE, see the API Warnings/Errors preference page, API Use tab, Invalid reference to system libraries option (there is a link to install the different fragments).
Comment 13 John Cortell CLA 2010-02-09 15:40:42 EST
It seems to me that using the objects hashcode as a reference-less handle to the object is unsound, as the JVM is explicit in that a VM should *try* to provide unique hashcode for live objects, but that it's not required to. There's a lot of good food for thought on this subject here:

   http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6321873

Perhaps I'm misinterpreting the fix, though...