JDK-4864304 : Improve memory consumption of Swing apps
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0,5.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS:
    generic,linux,solaris_2.6,solaris_7,solaris_8,solaris_9,solaris_10,windows_xp generic,linux,solaris_2.6,solaris_7,solaris_8,solaris_9,solaris_10,windows_xp
  • CPU: generic,x86,sparc
  • Submitted: 2003-05-15
  • Updated: 2017-05-16
  • Resolved: 2003-07-26
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
5.0 tigerFixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
There are a number of changes that could be done to Swing/AWT to
improve the memory footprint:

. Rewrite Autoscroller.
. Promote a handful of methods from JComponent to Container.
. Move seldomly used fields to a separate data structure.

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b13
14-06-2004

EVALUATION Yes. This needs to be more fully investigated to determine the impact and the best bang for the buck. ###@###.### 2003-05-14 The following was done: SwingGraphics has been nuked. setXXXSize and isXXXSizeSet have been promoted to Component Removed EnableSerialization hack from JComponent, Component now has a hack. DebugGraphics is now only loaded when necessary. Rewrote Autoscroller Rewrote OverlayLayout to SharedOverlayLayout so that it can be shared and NOT cache anything. Removed JComponent._bounds, uses getX, getY, getWidth and getHeight now. Removed AbstractButton.accessibleIcon, not needed. Promoted JButton.defaultCapable to AbstractButton to avoid an extra field. Removed JLabel.accessibleIcon Made JComponent.alignmentX/alignmentY floats vs Float. Removed JComponent.paintImmediatelyClip and tmpRect, instead a cache of Rectangles is kept. Made clientProperties into an ArrayTable. Made the following into client properties: htmlView, ancestorNotifier, transfer, inputVerifier. JScrollPane/MetalScrollPaneUI/BasicScrollPaneUI tweaks to allow for a null horizontal scrollbar JPopupMenu calls enableEvents instead of adding a MouseListener. Combined actions that ToolTipManager creates into a UIAction. MetalInternalFrameTitle no longer sets the accessible names of the icons, instead this is a promoted to basic and basic now overrides getAccessibleContext. This resulted in the following API changes: This request consists of five distinct changes. The first is promoting setXXXSize and isXXXSizeSet methods from JComponent to Component. This is done to reduce redundancy of fields between JComponent and Component. This resulted in the following new methods to Component: /** * Sets the preferred size of this component to a constant * value. Subsequent calls to <code>getPreferredSize</code> will always * return this value. Setting the preferred size to <code>null</code> * restores the default behavior. * * @param preferredSize The new preferred size, or null * @see #getPreferredSize * @see #isPreferredSizeSet * @since 1.5 */ public void setPreferredSize(Dimension preferredSize); /** * Returns true if the preferred size has been set to a * non-<code>null</code> value otherwise returns false. * * @return true if <code>setPreferredSize</code> has been invoked * with a non-null value. * @since 1.5 */ public boolean isPreferredSizeSet(); /** * Sets the minimum size of this component to a constant * value. Subsequent calls to <code>getMinimumSize</code> will always * return this value. Setting the minimum size to <code>null</code> * restores the default behavior. * * @param minimumSize the new minimum size of this component * @see #getMinimumSize * @see #isMinimumSizeSet * @since 1.5 */ public void setMinimumSize(Dimension minimumSize); /** * Returns whether or not <code>setMinimumSize</code> has been * invoked with a non-null value. * * @return true if <code>setMinimumSize</code> has been invoked with a * non-null value. * @since 1.5 */ public boolean isMinimumSizeSet(); /** * Sets the maximum size of this component to a constant * value. Subsequent calls to <code>getMaximumSize</code> will always * return this value. Setting the maximum size to <code>null</code> * restores the default behavior. * * @param maximumSize a <code>Dimension</code> containing the * desired maximum allowable size * @see #getMaximumSize * @see #isMaximumSizeSet * @since 1.5 */ public void setMaximumSize(Dimension maximumSize); /** * Returns true if the maximum size has been set to a non-<code>null</code> * value otherwise returns false. * * @return true if <code>maximumSize</code> is non-<code>null</code>, * false otherwise * @since 1.5 */ public boolean isMaximumSizeSet(); These properties will fire a property change event when they are changed (they are bound). We will document this in Component's addPropertyChangeListener method. This will result in adding the following to addPropertyChangeListener's javadoc: * <li>this Component's preferred size ("preferredSize")</li> * <li>this Component's minimum size ("minimumSize")</li> * <li>this Component's maximum size ("maximumSize")</li> * <li>this Component's name ("name")</li> This resulted in removing the following 3 methods from JComponent (they are now inherited): /** * Returns true if the minimum size has been set to a non-<code>null</code> * value otherwise returns false. * * @return true if <code>minimumSize</code> is non-<code>null</code>, * false otherwise * @since 1.3 */ public boolean isMinimumSizeSet(); /** * Returns true if the preferred size has been set to a * non-<code>null</code> value otherwise returns false. * * @return true if <code>preferredSize</code> is non-<code>null</code>, * false otherwise * @since 1.3 */ public boolean isPreferredSizeSet(); /** * Returns true if the maximum size has been set to a non-<code>null</code> * value otherwise returns false. * * @return true if <code>maximumSize</code> is non-<code>null</code>, * false otherwise * @since 1.3 */ public boolean isMaximumSizeSet(); To improve memory needed for autoscrolling it was necessary for JComponent to override the processMouseEvent method, the spec will read: /** * Processes mouse events occurring on this component by * dispatching them to any registered * <code>MouseListener</code> objects, refer to * {@link java.awt.Component#processMouseEvent(MouseEvent)} * for a complete description of this method. * * @param e the mouse event * @see java.awt.Component#processMouseEvent * @since 1.5 */ protected void processMouseEvent(MouseEvent e); To optimize the heap size of AbstractButton we need to override a couple of methods from the superclass, they are: /** * Adds the specified component to this container at the specified * index, refer to * {@link java.awt.Container#addImpl(Component, Object, int)} * for a complete description of this method. * * @param comp the component to be added * @param constraints an object expressing layout constraints * for this component * @param index the position in the container's list at which to * insert the component, where <code>-1</code> * means append to the end * @exception IllegalArgumentException if <code>index</code> is invalid * @exception IllegalArgumentException if adding the container's parent * to itself * @exception IllegalArgumentException if adding a window to a container * @since 1.5 */ protected void addImpl(Component comp, Object constraints, int index); /** * Sets the layout manager for this container, refer to * {@link java.awt.Container#setLayout(LayoutManager)} * for a complete description of this method. * * @param mgr the specified layout manager * @since 1.5 */ public void setLayout(LayoutManager mgr); The remaining changes clarify specification that was documenting implementation when it should not have been. These changes allow us to reduce the per instance size of JButtons and JViewports. javax.swing.AbstractButton.createChangeListener was documenting implementation details. Change the @return from: * @return the new <code>ButtonChangeListener</code> */ protected ChangeListener createChangeListener(); to: * @return a <code>ChangeListener</code> */ protected ChangeListener createChangeListener(); javax.swing.JViewport.createLayoutManager was documenting implementation details. Change the javadoc from: /** * Subclassers can override this to install a different * layout manager (or <code>null</code>) in the constructor. Returns * a new <code>ViewportLayout</code> object. * * @return a <code>LayoutManager</code> */ protected LayoutManager createLayoutManager(); to: /** * Subclassers can override this to install a different * layout manager (or <code>null</code>) in the constructor. Returns * the <code>LayoutManager</code> to install on the <code>JViewport</code>. * * @return a <code>LayoutManager</code> */ protected LayoutManager createLayoutManager(); I've attached two files that show the difference in instance size of various swing widgets. The 1.4.2 file is relative to 1.4.2 and includes some other tuning that was done as part of the Synth work. The 1.5 file is relative to b8 of tiger. Size calculation was done by creating one instance of a particular widget and taking a snapshot of the heap, then creating 11 instances and calculating the delta and dividing 10. ###@###.### 2003-07-25
25-07-2003