text: Products and Services
  Downloads
  Store
  Support
  Education
  Partners
  About
  Oracle Technology Network
  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
  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:
  ###@###.### 2005-06-13 23:13:43 GMT
  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
  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