JDK-6255588 : JDK windows printing implementation leaks GDI objects.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0,1.4.2_10,5.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,windows_2000,windows_xp
  • CPU: generic,x86
  • Submitted: 2005-04-14
  • Updated: 2010-12-08
  • Resolved: 2005-05-31
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 JDK 6
1.4.2_12Fixed 6 betaFixed
Related Reports
Relates :  
Relates :  
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
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
14-04-2005

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
14-04-2005

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
14-04-2005