United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4766813 : Java2D is leaking GDI resources when rendering to acc. offscreen surfaces

Details
Type:
Bug
Submit Date:
2002-10-22
Status:
Resolved
Updated Date:
2003-04-21
Project Name:
JDK
Resolved Date:
2003-04-21
Component:
client-libs
OS:
windows_xp
Sub-Component:
2d
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.4.0,1.4.1
Fixed Versions:
5.0 (tiger)

Related Reports
Relates:

Sub Tasks

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


                                     
2004-06-14
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
                                     
2003-04-04
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
                                     
2003-03-26
WORK AROUND

Disable offscreen acceleration:
java -Dsun.java2d.ddoffscreen=false TheExample

###@###.### 2002-11-22
                                     
2002-11-22



Hardware and Software, Engineered to Work Together