memory leaking [message #376894] |
Mon, 28 July 2008 14:35 |
Tom Eugelink Messages: 825 Registered: July 2009 |
Senior Member |
|
|
I'm using EclipseLink 1.0 in a stand alone Swing application which suffers from memory leaking.
I would really really appriciate it, if anyone can help me get on track again, because I'm completely stuck.
I know it is much to ask, but... Well... If I do not ask...
The application has two JFrames open, both for managing "Relations".
After working with the application for a while, the memory runs full: currently I have a memory dump of about 400 MB after only 3 hours of work.
If I examine the memory dump, I see the 2 screens (RelationObjectNavigator), 4 EntityManagers (correct), but out of the total of 880000 objects, 360000 are UnitOfWorkQueryValueHolder and 230000 are ReadObjectQuery or ReadAllQuery objects.
So just three classes are responsible for 67% of the classes.
Now, realistic memory usage would be something below 100 MB instead of almost 500.
If I inspect a few of the UnitOfWorkQueryValueHolder objects path-to-GC using Eclipse's MAT, I cannot explain why the objects still exist are are not GCed (I did do a GC before creating the memory dump).
For example the following path-to-GC:
1. org.eclipse.persistence.internal.indirection.UnitOfWorkQuery ValueHolder @ 0x1cba6398
2. valueHolder - org.eclipse.persistence.indirection.IndirectList @ 0x1cb42498
3. iRelationsWhereIAmRelation - nl.reinders.bm.Relation @ 0x1cb05730
4. [1] - java.lang.Object[16] @ 0x1cc81950
5. elementData - java.util.ArrayList @ 0x1cc78c40
6. val$returnSearchResult - org.tbee.swing.jpa.JpaEntitySearchBuilder$13 @ 0x1cc44ff8
7. [3] - java.lang.Object[4] @ 0x1cc2ce10
8. listenerList - javax.swing.event.EventListenerList @ 0x1cbf57f8
9. listenerList - javax.swing.JButton @ 0x1cbd37a8
10. val$lOkButton - org.tbee.swing.jpa.JpaEntitySearchBuilder$14 @ 0x1cb99c28
11. b - java.awt.AWTEventMulticaster @ 0x1cb37ca0
Analysis:
1&2&3: the Relation entity 0x1cb05730 has a lazy loading list of other Relation entities (forgive the property name).
4&5: the Relation object is entry [1] in the ArrayList
6: the ArrayList is held in the variable 'returnSearchResult' in JpaEntitySearchBuilder 0x1cc44ff8
7&8&9&10: the JpaEntitySearchBuilder is held at index [3] in the listenersList of the OkButton 0x1cb99c28.
I do not understand why this is not garbage collected. To show the code path, it starts in one of the JFrames; it has a filter Jbutton
// filter (this is an instance level button)
iFilter.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e)
{
...
// builder (obtained from the cache or created)
JpaEntitySearchBuilder<T> lJpaEntitySearchBuilder = JpaEntitySearchBuilder.obtainJpaEntitySearchBuilder(getModel ().getEntityClass(), getSearchPrefix());
// search
List<T> lList = new ArrayList<T>(); // we can have only one return value, so the list is provided as a parameter
T lEntity = lJpaEntitySearchBuilder.searchSingleDialog( iSearch, Internationalization.get().translate(JpaObjectNavigatorBar.t his, "search"), lList );
// filter
// it is weird: even though we create our own list here, two bars within the same application overwrite each other.
// So we need to create yet another list here.
if (lList.size() > 0) getModel().doFilter( new ArrayList<T>(lList), lEntity );
else iFilter.setSelected(false);
// return
JpaEntitySearchBuilder.returnJpaEntitySearchBuilder(lJpaEnti tySearchBuilder);
}
With one minor step in between, this ends up in JpaEntitySearchBuilder:
protected List<T> searchDialog(Component component, String title, final int selectMode, final List<T> returnSearchResult)
{
...
final JButton lOkButton = new JButton( Internationalization.get().translate(this, "ok"), new ImageIcon(JpaObjectNavigatorBar.class.getResource("icon_ok.png ")) );
lOkButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e)
{
...
// returnSearchResult
if (returnSearchResult != null)
{
returnSearchResult.clear();
for (int lIdx = 0; lIdx < lJpaEntitySearchResultTableModelFinal.getRowCount(); lIdx++)
{
T lEntity = lJpaEntitySearchResultTableModelFinal.getEntity( lTableSorter.convertRowIndexToModel( lIdx ) );
returnSearchResult.add( lEntity );
}
}
...
}
}
This is it! A local list is instantiated in the action listener of the filter button, this is handed over to the JpaEntitySearchBuilder, which copies the data in the JpaEntitySearchResultTableModel into the list.
The when the action listener exits, the list should be GCed!
Now, my comment after the search method worries me. It appears there are conflicts between lists, even though they are separate lists.
Can it be the "final" on parameters in searchDialog has some unexpected side effects?
|
|
|
|
|
|
|
|
|
|
Re: memory leaking [message #377451 is a reply to message #377448] |
Thu, 31 July 2008 14:33 |
Tom Eugelink Messages: 825 Registered: July 2009 |
Senior Member |
|
|
> You can set this as a persistence.xml property, or a persistence unit
> property.
Ah, ok.
> But you should probably fix the memory leak in your application
> instead. From your stack you were adding your JpaEntitySearchBuilder as
> an event listener to the button, so as long as the button exists, so
> will your event listener, and you event listener was holding onto the
> list of Entityies which held everything else. You should clear the
> reference in your event listener after it executes.
Not quite, it is an anonymous inner class inside the method that is added. Everything is method-local now, so there can't be a handing reference anymore.
It turns out there is a serious bug in the JDialog handling in Java 1.6. Never the less, that is not the cause of my problems.
It also turns out that windows task manager is a lousy way to check memory usage (try minimizing all windows of an application while the TM is open).
> In general also clearing your EntityManager when your done with it would
> be a good idea.
It is cleared, but this method is not responsible for that, but the caller does that.
Thanks!
Tom
|
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.07909 seconds