JDK-4774960 : Graphics2D.drawLine() with dashed strokes leaks memory
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.3.1,1.4.0,1.4.1,1.4.2,5.0
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,solaris_8,windows_2000
  • CPU: generic,x86
  • Submitted: 2002-11-06
  • Updated: 2016-06-18
  • Resolved: 2003-03-21
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
1.4.1_03 03Fixed 1.4.2Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
When using the 1.4 Jre in Win32, calling drawLine() on a Graphics2D object seems to leak very large amounts of memory from the VM to the OS.  When I run the attached code and then cause the application to repaint repeatedly, I can see from monitoring the process's memory usage in Task Manager that the application's VM instance starts taking up more and more RAM.  By making the application repaint one or two dozen times, I can easily force the memory usage to go over 100MB.  Moving Task Manager around on top the application seems to be the simplest way to get lots of repaints to occur.


import java.awt.*;

public class DashFrame
  extends java.awt.Frame
{
  public void paint(Graphics g)
  {
    Graphics2D g2 = (Graphics2D) g;  
    g2.setColor(Color.red);
    
    for (int i = 0; i < getWidth(); i += 10)
    {
      for (int j = 0; j < getHeight(); j+= 10)
      {  
        Stroke old = g2.getStroke();
        g2.setStroke(stroke);
        g2.drawLine(i, j, i+8, j);
        g2.setStroke(old);          
      }
    }
  }      

  private static Stroke stroke = new BasicStroke(
    1, 
    BasicStroke.CAP_BUTT, 
    BasicStroke.JOIN_BEVEL, 
    0f, 
    new float[] { 1, 1 }, 
    0f);

  public static void main(String[] args)
  {
    Frame f = new DashFrame();
    f.setBounds(100, 100, 600, 400);
    f.setVisible(true);
  }  
}

Internal testing shows:

-  When running the application with the OptimizeIt profiler, the process memory usage does not show the same behavior.  Very large instances of certain objects are created upon repaint (such as Finalizers in particular), although the number of these instances is reduced if GC is forced.

-  This problem can also be reproduced on 1.3.1 (1.3.1_02 and 1.3.1_06 were tested), although memory usage does not increase as quickly as it does with 1.4.1.

-  The problem does not exist with a Stroke without a dashed pattern (i.e. a Stroke created with only four arguments).

-  Similar behavior can also be seen on Solaris 8 by monitoring with prstat.

-  This problem looks similar that described in bug 4667078.  

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.4.1_03 mantis-beta tiger FIXED IN: 1.4.1_03 mantis-beta tiger INTEGRATED IN: 1.4.1_03 mantis-b19 mantis-beta tiger tiger-b22 VERIFIED IN: mantis-beta
14-06-2004

SUGGESTED FIX > Date: Mon, 17 Mar 2003 11:39:09 -0800 > From: Jim Graham <###@###.###> > To: Jeannette Hung <###@###.###> > cc: Jim Graham <###@###.###> > Subject: Re: mantis escalations > MIME-Version: 1.0 > Content-Transfer-Encoding: 7bit > Content-Disposition: inline > > Since we're no longer actively working on Mantis then it should be OK > to go back into Mantis as is. > > It would be nice for someone on our team to take a look at cleaning it > up by adding some new APIs and/or cleaning up the calling sequence in > the Ductus code. Maybe Sergi could look at this while he is looking at > the overflow problems there. In particular, they use a JNI GlobalRef > to hang on to the subsequent object in the chain and they do that > whether or not they need a native reference and that just mucks up the > GC of those objects. I wanted to get rid of that extra reference for > the long run...
11-06-2004

EVALUATION Commit to tiger. ###@###.### 2002-11-06 The problem is inter-object finalizations. The objects sun.dc.pr.PathDasher & sun.dc.pr.PathStroker depend finalizer thread to free native memory. In addition that, these objects refer to each other and hold native references at java level. The fix is to dispose the objects when they are no longer needed. Thanks to Jim(flar) for his valuable suggestions around the fix. ###@###.### 2002-12-10 Fixes were added to patch releases of 1.4.1 and 1.4.2 and then an improved fix was added to Tiger. The fix in Tiger uses aggressive manual disposing of all of the geometry objects in typical cases and the recently added Disposer facility (a Ref based disposer that is much more aggressive than the built in finalization) for a case that is expected to be encountered relatively rarely. The memory utilization of some benchmarks that aggressively hammer on path dashing and widening showed that no garbage was being generated in either the Java heap or system memory - the process sizes remained flat over a period of time where they would have grown by about a Megabyte every couple of seconds before the fix. A side benefit of the aggressive disposing of the native data structures is increased performance due to less finalization traffic. The stroking operations were 20-40% faster depending on the operation and the platform (Windows showed the largest improvement of nearly 40% when using the BasicStroke.createStrokedShape() method in a tight loop). ###@###.### 2003-09-10
10-09-2003