United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6255588 : JDK windows printing implementation leaks GDI objects.

Details
Type:
Bug
Submit Date:
2005-04-14
Status:
Resolved
Updated Date:
2010-12-08
Project Name:
JDK
Resolved Date:
2005-05-31
Component:
client-libs
OS:
generic,windows_xp,windows_2000
Sub-Component:
2d
CPU:
x86,generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.4.0,1.4.2_10,5.0
Fixed Versions:

Related Reports
Backport:
Backport:
Relates:
Relates:

Sub Tasks

Description
The JDK's windows printing implementation is leaking GDI objects : 2 per job
seems typical but it's not a "per-job" leak.
Its observable in a process which creates and in some minimal way uses
one or more PrinterJobs as both a growth in native process size (not Java heap)
and in the windows task manager as a leak in GDI Objects (select the column
to view this).

A program as simple as this can demonstrate the problem:

import java.awt.print.*;

public class PT {

    public static void main(String[] args) {
        PrinterJob printerJob = PrinterJob.getPrinterJob();
        for (int i=0;i<10000;i++) {
            printerJob.defaultPage();
        }
    }
}
###@###.### 2005-04-14 21:14:29 GMT

                                    

Comments
WORK AROUND


Add the following code right after PrinterJob.getPrinterJob() :
     try {
         printerJob.setPrintService(printerJob.getPrintService());
        } catch (PrinterException e) {}
}

This triggers initialisation of the fields.

###@###.### 2005-04-14 21:14:29 GMT
                                     
2005-04-14
SUGGESTED FIX

The fix is for the internal functions which expect these values to be initialised to
first call initPrinter() which is the central and principal wasy of initialising
these. It may have some additional side-effects that aren't desirable for
these cases so that needs checking in to.

Since the freeing of these fields is performed in a finalize() method then
tests may still notice substantial accumulation of these GDI objects before
GC() kicks in. This is most likely to be observed in programs which generate
minimal garbage per printer job (unlikely) or starve the finaliser thread.
It may be unduly complex to move the freeing of these objects to "endDoc()"
as its possible an app may decide to call some API after returning from
print(), or even to not call print() at all. Migration of this to the
2D disposer mechanism (getting very popular!) would help.
###@###.### 2005-04-14 21:14:30 GMT

webrev available here:
http://javaweb.sfbay/jcg/1.6.0-mustang/2D/6255588/
###@###.### 2005-06-13 23:13:43 GMT
                                     
2005-04-14
EVALUATION

I noticed this growth when fixing 6186524 but wasn't able to track down
the cause until now.
Handles to a printer DC, DEVNAMES, and DEVMODE are stored in the WPrinterJob
object. These are retrieved in several places in native code. Some of these
do not use DEVMODE but do retrieve the DC and DEVNAMES. If they are null then
the call PrintDlg() to get values. validatePaper() correctly notes its
a "privateDC" but getDefaultPage() does not and that is the problem.

Every defaultPage() call that is made before the fields are set in
the PrinterJob gets its own DC and DEVNAMES and leaks its - having
forgot that it allocated them itself. Yuck.

Not all code paths are bound to trigger this as some may cause these fields
to be filled in before these fns are called, or they may not be called at
all. But it appears that many programs will trigger it. The offending
implementation of defaultPage() is called when an app calls
setPrintable(Printable) which is almost universal.
ie the extremely common two line pattern of

PrinterJob printerJob = PrinterJob.getPrinterJob();
printerJob.setPrintable(myPrintable);

will cause a leak. This seems reproducible from 1.4.0 (merlin) onwards.
It looks as if it was introduced by the fix to 
4545985:Printerjob.defaultPage returns incorrect default page size
That fix also added a comment that it was expecting these to be already
initialised. Perhaps it was expected that user code could not reach
this function without a printer being initialised. That may have been true
then perhaps??
Also it looks like this was reported once before
4737016:PrinterJob.defaultPage() does not free resources in Windows
and the fix for that in 1.4.2 was not complete ?? 

###@###.### 2005-04-14 21:41:42 GMT

The same submitter observed that the workaround didn't cure all leaks.
The problem there was that whatever non-stock HPEN, HBRUSH or HFONT was
selected into the printDC at the time the job ended was not explicitly
deleted. This could cause up to 3 additional GDI Objects per job.
This fixes that.

I also found that the recent refresh printers work caused some new handle leaks as
it can start multiple notification threads. This will quickly fix that too.


###@###.### 2005-04-21 00:42:46 GMT
                                     
2005-04-14



Hardware and Software, Engineered to Work Together