Bug 561478 - memory leak in adaptable scope framework
Summary: memory leak in adaptable scope framework
Status: NEW
Alias: None
Product: GEF
Classification: Tools
Component: GEF FX (show other bugs)
Version: 5.1.0   Edit
Hardware: PC Windows 7
: P3 major (vote)
Target Milestone: ---   Edit
Assignee: gef-inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-03-26 05:16 EDT by girijanandan nucha CLA
Modified: 2020-03-27 08:20 EDT (History)
2 users (show)

See Also:


Attachments
the static map which is not cleared. (20.59 KB, image/png)
2020-03-26 05:21 EDT, girijanandan nucha CLA
no flags Details
visualvm memory dump (74.95 KB, image/jpeg)
2020-03-26 05:22 EDT, girijanandan nucha CLA
no flags Details
GC root showing reference held by launcher (28.51 KB, image/jpeg)
2020-03-26 12:40 EDT, girijanandan nucha CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description girijanandan nucha CLA 2020-03-26 05:16:25 EDT

    
Comment 1 girijanandan nucha CLA 2020-03-26 05:21:31 EDT
Created attachment 282231 [details]
the static map which is not cleared.
Comment 2 girijanandan nucha CLA 2020-03-26 05:22:06 EDT
Created attachment 282232 [details]
visualvm memory dump
Comment 3 Matthias Wienand CLA 2020-03-26 06:01:18 EDT
As discussed in the forum[1], the keys of this map are weakened, so en entry will be removed automatically when its key is garbage collected.

What is the context, i.e. when does a memory leak happen?

Looking at this memory snapshot, there is still a ZestFxRootPart present. That should be disposed when calling IViewer.dispose(). So you should find out why it is not garbage collected. (And maybe you can find a minimal leaking example.)

I would rather not provide means to clear the map as a last resort. Maybe we have to, though.

[1] https://www.eclipse.org/forums/index.php/t/1101831/
Comment 4 girijanandan nucha CLA 2020-03-26 11:57:18 EDT
Hi Matthias,

There was some issue with my code, preDestroy() call which sets the viewer reference to null was not getting called. After fixing the issue and waiting for around 2 hours for GC to collect keys of weak hashmap, it indeed clears the keys. Now ApaptableScope map is no loger holding the refernce of javafx objets. But still the leak exists (Please refer attached screenshot) 

Any idea why this leak exists ?

Context :
I have a javafx application rendered in a FXCanvas which is child of a eclipse component (our product component). Whenever i invoke the javafx feature and close it, this issue happens.

Thanks and Regards,
Giri
Comment 5 girijanandan nucha CLA 2020-03-26 12:40:41 EDT
Created attachment 282241 [details]
GC root showing reference held by launcher
Comment 6 Matthias Wienand CLA 2020-03-26 13:14:40 EDT
Thanks for sharing additional insights.

Alexander tried to come up with a test case to ensure that this map is cleared as it should be. However, he could not yet make it work, and neither could I.

While experimenting, it seems like the scopedInstances map strangely reports its size in comparison to its keySet() and values() (no keys, no values, but size=1).

Looking into a heap dump reveals that the key is removed, but the stored value somehow remains in a "segments" table (I will have to investigate further).

I experimented with different weak hash map implementations and noticed different behaviors.

I cannot yet conclude how to proceed.

As a workaround, you can clear the map using reflection, somewhat like this:

Class adaptableScopeClass = AdaptableScope.typed(IDomain.class).getClass();
Field scopedInstances = adaptableScopeClass.getDeclaredField("scopedInstances");
scopedInstances.setAccessible(true);
scopedInstances.get(null).clear();
Comment 7 girijanandan nucha CLA 2020-03-27 08:10:56 EDT
Thanks for the analysis Matthias.

I tried to clear the map using reflection but i get following compilation error. Am i doing something wrong ?

The type AdaptableScope<IDomain> is not visible

Thanks and Regards,
Giri
Comment 8 Alexander Nyßen CLA 2020-03-27 08:14:33 EDT
You cannot import the class as it has package visibility. What you can do is:

Object rootScope = AdaptableScopes.typed(Root.class);
assertNotNull(rootScope);
Field scopedInstancesField = rootScope.getClass()			.getDeclaredField("scopedInstances");
scopedInstancesField.setAccessible(true);
@SuppressWarnings("unchecked")
Map<IAdaptable, Map<Key<?>, Object>> scopedInstances = (Map<IAdaptable, Map<Key<?>, Object>>) scopedInstancesField.get(null);
Comment 9 Alexander Nyßen CLA 2020-03-27 08:15:24 EDT
The first line has to be replace with an Object variable pointing to the AdapterScope you use.
Comment 10 Matthias Wienand CLA 2020-03-27 08:20:01 EDT
I already posted that code in the comment above, but with a typo: AdaptableScope vs. AdaptableScopes. There I used IDomain.class, because that should be present.