JDK-6581899 : JTextField & JTextArea - Poor performance with JRE 1.5.0_08
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-07-18
  • Updated: 2011-05-18
  • Resolved: 2011-05-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other Other JDK 6 JDK 7
5.0u16-revFixed 5.0u17Fixed 6u12Fixed 7 b36Fixed
Description
FULL PRODUCT VERSION :
java version "1.5.0_08"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_08-b03)
Java HotSpot(TM) Client VM (build 1.5.0_08-b03, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP, Professional, Version 2002, SP2.

EXTRA RELEVANT SYSTEM CONFIGURATION :
Intel(R) Pentium(R) 4 CPU, 2.4 GHz, 1.00 GB of RAM

A DESCRIPTION OF THE PROBLEM :
Our application is completely applet-based with java swing UI. The application had been recently migrated from JRE 1.4.1_02 to 1.5.0_08.
Since the migration, it has been observed that the text field and text area  components show poor performance when typing some input text the on fields. The problem occurs in IE6 and IE7 browsers.

When typed some input in the text field, the component seems to hang for a short time before it reponds. The characters does not appear in the text field as and when a character is typed. The character appears in the field after a bit-while. Note that the field has no event listeners.

The time taken for a typed character to become visible on the field is approximately 0.010 ms with JRE 1.4 and 0.390 ms with JRE 1.5. This means, the performance degraded by nearly 40 times.

The delay is proportional to number of swing components in the screen and the complexity of the layout. More the number of swing UI components, much easier to replicate the issue.

Replacing the JTextField with JFormattedTextField did not help. Changing the windows appearance from "XP style" to "classic style" did not help.

The problem could not be replicated in Mozilla browser and applet viewer.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Launch TestApplet (source code attached) in internet explorer v6/7 and type some input in the text fields. The fields will respond sluggishly.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The typed text should appear  on the fields without delays.
ACTUAL -
When typed some input in the text field, the component seems to hang for a short time before it reponds. The characters does not appear in the text field as and when a character is typed. The character appears in the field after a bit-while. Note that the field has no event listeners.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
No errors. No excpetions.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
----------------------------------------------------------------------------------------------------
package test;

import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class TestApplet extends JApplet {

	private JPanel ivjJAppletContentPane = null;

	public void init() {
		setContentPane(getJAppletContentPane());
		setName("Test Applet");
	}

	private javax.swing.JPanel getJAppletContentPane() {
		if (ivjJAppletContentPane == null) {
			try {
				ivjJAppletContentPane = new javax.swing.JPanel();
				ivjJAppletContentPane.setName("JAppletContentPane");
				ivjJAppletContentPane.setBorder(new javax.swing.border.EtchedBorder());
				ivjJAppletContentPane.setLayout(null);
				for (int i=1; i<2000; i++) {
					JTextField ivjDescField = new javax.swing.JTextField();
					ivjDescField.setName("DescField");
					ivjDescField.setBounds(20, i*20, 215, 20);
					getJAppletContentPane().add(ivjDescField, ivjDescField.getName());
				}
			} catch (java.lang.Throwable ivjExc) {
				System.out.println(ivjExc);
			}
		}
		return ivjJAppletContentPane;
	}
}

  To test the applet in JRE 1.5, use the below HTML.
----------------------------------------------------------------------------------------------------

<HTML>
<HEAD>
<TITLE>AIQ</TITLE>
</HEAD>
<BODY>
<body bgcolor=#c0c0c0>
<div align="center">
<OBJECT
object classid ="clsid:CAFEEFAC-0015-0000-0008-ABCDEFFEDCBA" WIDTH = "300" HEIGHT = "10000" >
	<PARAM NAME = CODE VALUE = "test.TestApplet.class" >
	<PARAM NAME = ARCHIVE VALUE = "../jar/AIQApplet.jar" >

	<PARAM NAME="type" value="application/x-java-applet;version=1.5.0_08">
	<PARAM NAME="scriptable" value="false">
</OBJECT>
</div>
</BODY>
</HTML>

----------------------------------------------------------------------------------------------------

  To test the applet in JRE 1.4, use the below HTML.

<HTML>
<HEAD>
<TITLE>AIQ</TITLE>
</HEAD>
<BODY>
<body bgcolor=#c0c0c0>
<div align="center">
<OBJECT
object classid ="clsid:CAFEEFAC-0014-0001-0002-ABCDEFFEDCBA" WIDTH = "300" HEIGHT = "10000" >
	<PARAM NAME = CODE VALUE = "com.aig.aiq.userservices.swing.TestApplet.class" >
	<PARAM NAME = ARCHIVE VALUE = "../jar/AIQApplet.jar" >

	<PARAM NAME="type" value="application/x-java-applet;version=1.4">
	<PARAM NAME="scriptable" value="false">
</OBJECT>
</div>
</BODY>
</HTML>
----------------------------------------------------------------------------------------------------
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No work around found.

Comments
SUGGESTED FIX src/share/classes/sun/awt/EmbeddedFrame.java @@ -255,23 +255,25 @@ AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e); Set toTest; Component currentFocused = e.getComponent(); - Component last = getFocusTraversalPolicy().getLastComponent(this); toTest = getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); - if (toTest.contains(stroke) && (currentFocused == last || last == null)) { - if (traverseOut(FORWARD)) { + if (toTest.contains(stroke)) { + // 6581899: performance improvement for SortingFocusTraversalPolicy + Component last = getFocusTraversalPolicy().getLastComponent(this); + if ((currentFocused == last || last == null) && (traverseOut(FORWARD))) { e.consume(); return true; } } - Component first = getFocusTraversalPolicy().getFirstComponent(this); toTest = getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); - if (toTest.contains(stroke) && (currentFocused == first || first == null)) { - if (traverseOut(BACKWARD)) { + if (toTest.contains(stroke)) { + // 6581899: performance improvement for SortingFocusTraversalPolicy + Component first = getFocusTraversalPolicy().getFirstComponent(this); + if ((currentFocused == first || first == null) && (traverseOut(BACKWARD))) { e.consume(); return true; } } return false;
25-06-2008

EVALUATION The issue is a regression of the fix for 4930813 (Need a way to traverse focus out of EmbeddedFrame). Since jdk5 the EmdeddedFrame.dispatchKeyEvent method calls get[First|Last]Component method on each key event even if the key event doesn't follow to focus traveral. Then, the get[First|Last]Component methods (in case of SortingFocusTraversalPolicy) initiate enumeration and sorting for the focus cycle, these are an expensive operations. The fix is to acquire the first|last components only when the key is traversal key.
25-06-2008

EVALUATION I checked that performance impact is indeed due to the sorting mechanism in SortingFocusTranversalPolicy. Though I don't have any idea why it's not reproducible for a standalone app. The problem with the sorting logic is that it restarts enumeration & sorting on every focus operation for the whole focus cycle. A solution that comes to my mind is to track add/remove changes to a focus cycle root and when there're no changes - don't resort the container repeatedly.
20-05-2008