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.