Solved

Bug in JTextPane ??

Posted on 2003-10-28
4
890 Views
Last Modified: 2008-02-01
Hi,

I am facing huge memory leak problems with JTextArea/JTextPane. After considerable investigation, I found out that the Document associated with the component is not being GC'ed properly. I ran OptimizeIt and found out that the memory is being consumed by the JTextPane.setText() method. I have implmented a HTML viewer to display large amounts of HTML data and it is leaking memory like crazy on each successive execution. Any thoughts ??

JDK1.4.2_01, WinXP

Here is the code fragment:

public class ReportViewer extends BaseFrame implements FontChange_int
{
      private      String            cReport;            
      private boolean            testMode = false;      

      // Graphical components
      private      BorderLayout      cMainLayout;
      private      JButton            cClose;
      private      JTextPane      cRptPane;
      private      Button            cClose2;

      private ViewUpdater     cViewUpdater = null;

      // Constants
      final      static      int      startupXSize = 650;
      final      static      int      startupYSize = 500;

      // Methods
      public ReportViewer(String report, ReportMain main)
      {
            // BaseFrame extends JFrame
            super("Reports Viewer", true, startupXSize, startupYSize);
            testMode     = false;
            cReport      = report;
            cViewUpdater = new ViewUpdater();
            initialize();
      }

      public void initialize()
      {
            // Create main layout manager
            cMainLayout = new BorderLayout();
            getContentPane().setLayout(cMainLayout);

            // Quick button bar - print, export, save as
            JToolBar      topPanel = new JToolBar();
            topPanel.setBorder(new BevelBorder(BevelBorder.RAISED) );
            java.net.URL      url;

            topPanel.add(Box.createHorizontalStrut(10));

            url = Scm.class.getResource("images/Exit.gif");
            cClose = new Button(new ImageIcon(url), true);
            cClose.setToolTipText("Close Window");
            topPanel.add(cClose);
            getContentPane().add(topPanel, BorderLayout.NORTH);

            // Main view window - HTML
            cRptPane = new JTextPane();
            cRptPane.setContentType("text/html");
            cRptPane.setEditable(false);

            JScrollPane sp = new JScrollPane(cRptPane);
            getContentPane().add(sp, BorderLayout.CENTER);

            // Main button - Close
            JPanel      bottomPanel = new JPanel();
            url = Scm.class.getResource("images/Exit.gif");
            cClose2 = new Button(new ImageIcon(url), "Close");
            bottomPanel.add(cClose2);
            getContentPane().add(bottomPanel, BorderLayout.SOUTH);

            cClose.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                        closeWindow();
                  }
            });
            cClose2.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                        closeWindow();
                  }
            });

            show();
            cViewUpdater.setText(cReport);
            SwingUtilities.invokeLater(cViewUpdater);
      }


      protected void
      closeWindow()
      {
            super.closeWindow();

            // If I add the following lines, the GC reclaims
                // part of the memory but does not flush out the text
                // component as a whole
            
            /*Document doc = cRptPane.getDocument();
            try
            {
                  doc.remove(0,doc.getLength());
            }
            catch(Exception e) {;}
            doc=null; */
            
            cRptPane=null;
            cReport = null;
            cViewUpdater = null;
            dispose();
      }

      private class ViewUpdater implements Runnable
      {
            private String cText = null;

            public ViewUpdater() {;}

            public void
            setText(String text) {
                  cText = text;
            }
            
            public void
            run() {
                  cRptPane.setText(cText);
                  cRptPane.setCaretPosition(0);
                  cText = null;
            }
      }

      // Local main - for testing
      public static void main(String args[])
      {
            //new ReportViewer(str,comp);
      }
}


--
Sudarshan
www.spectrumscm.com

0
Comment
Question by:snraghav
  • 2
4 Comments
 
LVL 35

Expert Comment

by:TimYates
Comment Utility
> I ran OptimizeIt and found out that the memory is being consumed by the JTextPane.setText() method

Does the memory never get GCed?

How many references to this bit of memory does OptimizeIt say you have?

Do you run out of memory?
0
 

Author Comment

by:snraghav
Comment Utility
Nope the memory never gets GCed and grows linearly on each successive execution. OptimizeIt reports that a large number of Object[] and ints are being created by the JTextPane.setText() method. More detailed investigation revealed that the objects are being created by the DefaultStyledDocument's ElementBuffer.insert() method. For some reason, the Document and its contents are sticky even if I null out all the references. I even tried trapping the Document events by writing my own listener and unregistering the listener upon close, but it doesn't seem to help.

--
Sudarshan
0
 
LVL 3

Accepted Solution

by:
savalou earned 50 total points
Comment Utility
The javadocs for JEditorPane (superclass of JTextPane) says:
"This is implemented to remove the contents of the current document, and replace them by parsing the given string using the current EditorKit. This gives the semantics of the superclass by not changing out the model, while supporting the content type currently set on this component. The assumption is that the previous content is relatively small, and that the previous content doesn't have side effects. Both of those assumptions can be violated and cause undesirable results. To avoid this, create a new document, getEditorKit().createDefaultDocument(), and replace the existing Document with the new one. You are then assured the previous Document won't have any lingering state. "

So it doesn't look like the Document object ever gets destroyed (WAD).  Can you try to implement the above suggestion?
0
 

Author Comment

by:snraghav
Comment Utility
savalou,

It is a decent workaround. I found out that this has been an open bug with Sun since 1999 !! The solution still leaks about 70kb for each successive execution (maybe the newly created document is sticky) but I can live with it. 70kb is much better than the 10 Mb I was previously leaking :-)

Thanks a ton ...

Sudarshan
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

For customizing the look of your lightweight component and making it look lucid like it was made of glass. Or: how to make your component more Apple-ish ;) This tip assumes your component to be of rectangular shape and completely opaque. (COD…
Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now