JDK-4766813 : Java2D is leaking GDI resources when rendering to acc. offscreen surfaces
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0,1.4.1
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2002-10-22
  • Updated: 2003-04-21
  • Resolved: 2003-04-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
5.0 tigerFixed
Related Reports
Relates :  
Description

Name: jk109818			Date: 10/22/2002


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 :
Microsoft Windows XP [Version 5.1.2600]
also on
Microsoft Windows 98
Microsoft 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) 
======================================================================

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

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. ###@###.### 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. ###@###.### 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. ###@###.### 2003-04-04
04-04-2003

SUGGESTED FIX http://javaweb.sfbay.sun.com/jcg/1.5.0-tiger/2D/4766813 http://javaweb.sfbay.sun.com/jcg/1.5.0-tiger/2D/4766813.pit ###@###.### 2003-03-26
26-03-2003

WORK AROUND Disable offscreen acceleration: java -Dsun.java2d.ddoffscreen=false TheExample ###@###.### 2002-11-22
22-11-2002