Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4766813
Votes 1
Synopsis Java2D is leaking GDI resources when rendering to acc. offscreen surfaces
Category java:classes_2d
Reported Against 1.4 , 1.4.1
Release Fixed 1.5(tiger)
State 10-Fix Delivered, bug
Priority: 4-Low
Related Bugs 4848001
Submit Date 22-OCT-2002
Description




FULL PRODUCT VERSION :

java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)

AND

java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

FULL OPERATING SYSTEM VERSION :
 customer  Windows XP [Version 5.1.2600]
also on
 customer  Windows 98
 customer  Windows ME

A DESCRIPTION OF THE PROBLEM :
when starting my program and clicking on the button again
and again, not only the program will crash and will not
draw any more, the os graphical environment has also a
lack of ability to draw for instance popup menus correct.
A reebot is required.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Start the programm by "java TheExample"
2. Click on the button again and again until the
Frame won't repaint any more and all circles have
become white.

EXPECTED VERSUS ACTUAL BEHAVIOR :
you should be able to click as much as you like and
the frame should paint the circles always and without
questions :o)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TheExample extends JFrame
{
	MyComponent mycomp = new MyComponent();
	
	TheExample()
	{
		Container c = getContentPane();
		c.setLayout(new BorderLayout() );
		
		JLabel label = new JLabel("When clicking on the button 300
ovals will be drawn at random");
		JButton button = new JButton("Many colorful ovals");
		
		c.add(label, BorderLayout.NORTH);
		c.add(button, BorderLayout.SOUTH);
		
		c.add(mycomp, BorderLayout.CENTER);
		
		button.addActionListener(
			new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					mycomp.shuffle();
				}
			}
		);
		
		setSize(640, 480);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	}
	
	public static void main(String[] ufz)
	{
		TheExample example = new TheExample();
		example.show();
	}
}

class MyComponent extends JComponent
{
	Circle circles[] = new Circle[300];
	
	MyComponent()
	{
		shuffle();
	}
	
	public void shuffle()
	{
		for (int i=0; i<circles.length; i++)
		{
			int x = (int)(Math.random() * getSize().width);
			int y = (int)(Math.random() * getSize().height);
			int width = (int)(Math.random() * 100);
			int height = (int)(Math.random() * 100);
			
			int r = (int)(Math.random() * 256);
			int g = (int)(Math.random() * 256);
			int b = (int)(Math.random() * 256);
	
			Color color = new Color(r, g, b);
			
			circles[i] = new Circle(x, y, width, height, color);
		}
		
		this.repaint(1);
	}
	
	public void paint(Graphics g)
	{
		for (int i=0; i<circles.length; i++)
		{
			int x = circles[i].getX();
			int y = circles[i].getY();
			int w = circles[i].getWidth();
			int h = circles[i].getHeight();
			Color c = circles[i].getColor();
			
			g.setColor(c);
			g.fillOval(x, y, w, h);
		}
	}
	
	private class Circle
	{
		private int x, y, width, height;
		private Color color;
		
		Circle(int x, int y, int width, int height, Color color)
		{
			this.x = x;
			this.y = y;
			this.width = width;
			this.height = height;
			this.color = color;
		}
		
		public int getX()
		{
			return x;
		}
		
		public int getY()
		{
			return y;
			
		}
		
		public int getWidth()
		{
			return width;
		}
		
		public int getHeight()
		{
			return height;
		}
		
		public Color getColor()
		{
			return color;
		}
	}
}
---------- END SOURCE ----------
(Review ID: 164615) 
======================================================================
Work Around
Disable offscreen acceleration:
java -Dsun.java2d.ddoffscreen=false TheExample

  xxxxx@xxxxx   2002-11-22
Evaluation
The problem is that we're leaking GDI resources pretty badly when doing GDI rendering to offscreen surfaces.
For example, we're creating a new Brush on any GetDC but never releasing it.
Same with Pens. Windows Task manager can show the leak (turn on the
'GDI Objects' column).

Releasing Brushes fixed the problem with the testcase in the description.
Win32SurfaceData currently does much better job with dealing with GDI 
resources (like caching Brushes, last color, clip, etc).
Similar funcionality has to be implemented for Win32OffScreenSurface.

The bug is reproducible since 1.4.0. My machine is WindowsXP. I'd imagine
that the consequenses of this bug are severe on Win9x where GDI resources
are very limited. Even on WinXP it does weird things to the system.

  xxxxx@xxxxx   2002-11-22

The fix was to cache the gdi resources in ThreadLocalStorage and make sure
we release them when appropriate.

We were also leaking resources stored in TLS, so the fix uses Disposer
to release those when the associated thread is gone.

  xxxxx@xxxxx   2003-03-26

Note that the Suggested fix is updated to include a fix for PIT failure
caused by the initial fix.
>   Regression test: test/sun/awt/image/PNGImageDecoder/PngTest
>   can be used to reproduce the problem and verify the fix: run it on
>   windows, maximize the frame. The desktop becomes distorted after
>   a while due to GDI resources exaustion.

  Basically, the problem is that in certain conditons we may run into
  situation when we won't be releasing the dcs, but just putting them
  on the list of dcs to be released (aka the 'passiveDCList').

  This was caused by the 'last minute very safe change' (c) that I put
  into the original fix, and which was not properly tested: in
  Win32SurfaceData, instead of directly releasing the DC by invoking
  SendMessage, I decided to just move it to the passive dc list,
  assuming the next time someone releases any DC, they all will be
  freed.

  So if the same thread renders to an offscreen image, an then to the
  screen and so on, alternating, we'd be putting the dc to the dc
  list while rendering offscreen, and then requesting a new DC when
  rendering to the screen.

  xxxxx@xxxxx   2003-04-04
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang