|
Quick Lists
|
|
Bug ID:
|
6264013
|
|
Votes
|
1
|
|
Synopsis
|
Infinite Recursion on EDT causes StackOverflowError
|
|
Category
|
java:classes_swing
|
|
Reported Against
|
|
|
Release Fixed
|
mustang(b96),
5.0u10(b02) (Bug ID:2140846)
|
|
State
|
10-Fix Delivered,
bug
|
|
Priority:
|
2-High
|
|
Related Bugs
|
4178589
|
|
Submit Date
|
02-MAY-2005
|
|
Description
|
When running the Yokogawa applet-based application an infinite recursion happens on the EDT with j2se 5.0 u2.
The silk-automated test opens and closes windows repeatedly for about 1 day. Each window is a new applet. After running for 1 day, an attempt to close an applet window causes java.lang.StackOverflowError caused by awt infinite recursion as indicated below. A popup comes up and says "Java General Exception", the stack trace is as follows:
Exception in thread "AWT-EventQueue-10640" java.lang.StackOverflowError
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
.............................(same frames repeated many more times)
The java console log is attached to this bug report. Thread dump is attached as well.
The application is still running in Sun's Santa Clara QA lab. Please contact submitter if help with diagnosing this issue is needed.
xxxxx@xxxxx 2005-05- customer 00:03:25 GMT
|
|
Work Around
|
While looking at the AppContext.dispose() code, I thought of a possible workaround. During the course of the dispose() method, all of the AppContext's ownerless windows are also dispose()d. By overriding Frame.dispose() to call LookAndFeel.uninitialize() and creating a realized but unshown Frame, we can avoid leaking AWTEventListeners.
...
class WorkaroundWindow extends Frame {
public WorkaroundWindow() {
super();
pack();
}
public void dispose() {
super.dispose();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
LookAndFeel laf = UIManager.getLookAndFeel();
if (laf != null) {
laf.uninitialize();
}
}
});
}
}
public void start() {
WorkaroundWindow ww = new WorkaroundWindow();
}
...
Putting the laf.uninitialize() call in an invokeLater() ensures it happens after all top-levels have been disposed by the AppContext. Obviously this is a bit of a kludge, but it does work (at least with my test case). Be very careful not to prematurely dispose() the workaround window, as it will mess up the LookAndFeel for the rest of your GUI!
|
|
Evaluation
|
Seems this occur because of recursive algorithm inside AWTEventMulticaster: we call to
ToolkitEventMulticaster.remove(l) then to
AWTEventMulticaster.removeInternal(l, l1) and then we get loop like:
AWTEventMulticaster.remove -> AWTEventMulticaster.removeInternal() -> AWTEventMulticaster.remove() ->... and so on.
The bug might be reproduced with a small test in Comments section. All we need is to put a large number of AWTEventListeners (I use 6000) into Toolkit and then remove one of them. Each remove will cause StackOverflowException.
I wonder if possible to modify Yokogawa applet and verify that listeners correctly removes after they are not needed anymore.
xxxxx@xxxxx 2005-05-11 14:01:51 GMT
After a further investigation it's likely the problem is in JDK; more precisely in Container.lightweightDispatcher class.
Initially we thought that application itself doesn't handle listeners correctly. Now I see that listeners are added/remove on mouseEntered/Exited events. This is reasonable and expected behavior but we probably may not handle them right on non-standard situations like window closing, ALT-TAB etc. We should inversitgate it better. Belive I would be able to write a test demonstrating the issue without applet and that test suite.
Posted Date : 2006-06-13 13:05:46.0
I verified a hierarchy of components as they created in browser:
a Frame includes an embedded Frame which in turn includes Applet.
To get a leak (believe we just don't erase AWTListener somewhere in) I repeatedly creating and closing these Frames but the number of listeners doens't grow. Seem this approach is not exactly the same as in original application.
Posted Date : 2006-06-26 15:01:23.0
I could reproduce the problem locally with an EmbeddedFrame owning JApplet(Applet - doesn't matter). The test shows the increasing number of AWTEventListeners in toolkit whereas we invoke add/remove correctly. Suppose it's a defect in Toolkit implementation. The bug reproducible with JDk6.0 as well as JDK1.5.0.
Posted Date : 2006-06-27 15:12:24.0
Applet creation supposes addition of an Applet into EmbeddedFrame. Standalone test emulates this. Though just Frame.add(new Applet()) doesn't shows the problem.
Each instance (a frame and an applet) initilizes it's own Container.LightweightDispatcher class. It implements AWTEventListener so is ready to be integrated into Toolkit with addAWTEventListener(). But removing of that listener happens from the different toplevel instances i.e. one of LightweightDispatchers constructed and pushed as a listener into Toolkit on applet constuction.
In turn on disposing of that frame another LightweightDispatcher is attempted to be eliminated from Toolkit by that frame. Here is the contradiction: Toolkit is using a HashMap to store all listeners in. Once it receives a request to erase non-existing listener another one is still there.
The problem only reproducible with lightweight component in that applet. I noticed that mouse should be positioned over the applet to get this defect to appear.
Posted Date : 2006-06-29 11:54:59.0
The defect symptoms comes to an awt issue. A component in a frame is receiving MouseExited on frame's dispose() on X11. But it doesn't on Win32.
As the AWTEventListener lightweightDispatcher would only be disposed when MouseExited comes then it stays the same on Win32.
That this is a native behavior and we should try to workaround it. Suppose we may track dispose and clear lightweightDispatcher explicitly by ourselves without that missed mouse event.
Posted Date : 2006-07-03 11:52:16.0
In a standalone application we may dispose EmbeddedFrame by ourself and it solves the problem - peer is disposed and container is removeNotifi'ed. This like a correct application should behave.
But ordinary applet can't access EmbeddedFrame and it should happen on Frame.dispose(). AWT does nothing to free embedded frame in that case because frame doesn't take into account its embbeded frame if any. Fortunately it works fine on Linux because that MouseExited event initiates lightweightDispatcher disposal. But I'm not sure that EmbeddedFrame is also eliminates.
So it would be great to dispose embedded frame explicitly and not rely on ExitedEvent.
Posted Date : 2006-07-03 14:01:29.0
Previous statement about undisposed EmbeddedFrame is not quite true. That time I thought it's a problem with plugin that doesn't dispose embedded frame object on WindowClosing.
At least I'm not able to emulate the case in my environment without Yokogava application(I'm using simple applet). All listeners are being removed properly and every embedded frame is being disposed on time.
Posted Date : 2006-07-04 11:27:56.0
I put a dump of all listeners in Toolkit.addAWTEventListener and found that all remained items are javax.swing.plaf.basic.BasicLookAndFeel$PopupInvocationHelper.
(Since JDK6.0 it calls javax.swing.plaf.basic.BasicLookAndFeel$AWTEventHelper but I can't even try to reproduce it with Mustang)
Looking on BasicLookAndFeel I noticed that BasicPopupMenuUI is not clearing listener.
It's reasonable to make an explicit removal in uninstallListeners() but it doesn't have any effect - the bug is still reproducible.
A pair of standalone tests doesn't recreate the defect.
Posted Date : 2006-07-11 14:03:30.0
I figured out a way to reproduce this with a standalone test case (attached). The test is basically just a JButton (w/ a popup) that dumps the list of AWTEventListeners when clicked. I put the applet into a signed .jar.
To reproduce the bug:
1) open a new tab in your browser
2) run the applet, and click the button to see the list of AWTEventListeners dumped to the Java console
3) close the tab (you need to have another browser tab/window open so the browser will stay open)
4) goto 1
Each time through the loop, an additional BasicLookAndFeel$PopupInvocationHelper is added to the list. The current theory is that when applet quits, its AppContext disappears before Swing has a chance to remove the listener.
(Note that running multiple copies of the applet at the same time does NOT cause additional listeners to be added - presumably they all run in the same AppContext).
Posted Date : 2006-07-14 22:04:38.0
To fix this bug, we need to alert BasicLookAndFeel when its AppContext is being disposed so that the LAf can uninitialize() itself.
Posted Date : 2006-08-04 20:10:28.0
|
|
Comments
|
Submitted On 29-AUG-2005
ChristyLThomas
I'm having the same problem. Is there a way to tell if the listeners are being removed properly (when they are no longer needed)? So the problem doesn't occur. Is there a tool for tracking listenerers?
I also saw this with 1.5.0_03
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.awt.AWTEventMulticaster.mouseEntered(AWTEventMulticaster.java:241)
at java.awt.AWTEventMulticaster.mouseEntered(AWTEventMulticaster.java:241)
at java.awt.AWTEventMulticaster.mouseEntered(AWTEventMulticaster.java:241)
at java.awt.AWTEventMulticaster.mouseEntered(AWTEventMulticaster.java:241)
at java.awt.AWTEventMulticaster.mouseEntered(AWTEventMulticaster.java:241)
.....(the above repeats for a while)
Submitted On 31-AUG-2005
thetan
try generified java.awt.Component.getListeners() and then remove.
Suppose any profiler might be used as a listener-tracker as they are only classes. :)
Submitted On 04-JUL-2006
thetan
ChristyLThomas, may you please provide a test representing your issue?
Thanks,
--Andrei
Submitted On 25-JUL-2006
ChristyThomas
This was happening in our application when we left it open for a while. We were continuously adding adding MouseListeners to the same component when we didn't need to be.
Instead of this:
c.addMouseListener ( mouseListener ) ;
c.addMouseMotionListener ( mouseListener ) ;
We are now doing this:
boolean addListener = true;
EventListener[] ev = c.getListeners( MouseListener.class );
for( int i =0; i < ev.length; i++ )
{
if( ev[i] == mouseListener )
{
addListener = false;
break;
}
}
if( addListener )
{
c.addMouseListener ( mouseListener ) ;
c.addMouseMotionListener ( mouseListener ) ;
}
I was looking for a way to debug the problem on our end, but did eventually determine our problem.
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|
|
|
 |