JDK-4068618 : Motif FontPeer needs to be disposed to prevent memory leak
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.1,1.1.3,1.1.4,1.1.5,1.1.6,1.1.7
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,solaris_2.5.1,solaris_2.6
  • CPU: generic,sparc
  • Submitted: 1997-07-30
  • Updated: 2013-11-01
  • Resolved: 1999-01-11
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 Other Other
1.1.6_003 b03Fixed 1.1.7Fixed 1.1.8Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description
Name: rlT66838			Date: 07/30/97

Software: Solaris 2.5.1
Hardware: Ultra Sparc 1

The following source core makes the Java VM grow in
size indefinitely indicating a memory leak in the VM
or the Solaris motif libraries.

Here's the java source code:

import java.awt.*;

public class MemoryLeak7
{
	public static void main( String args[] )
	{
		for( ;; )
		{
			for( int i = 0; i < 16; i++ )
			{
				Frame frame = new Frame();
				frame.setSize( 300, 300 );
				frame.setTitle( "Leaky Frame" );
				frame.setVisible( true );
				frame.setVisible( false );
				frame.dispose();
				frame = null;
			}
			System.gc();
			System.runFinalization();

			try
			{
				System.out.println( "---------- Sleeping ----------" );
				Thread.currentThread().sleep( 5000 );
				System.out.println( "------ Finished Sleeping ------" );
			}
			catch( Exception e )
			{
				System.err.println( "Thread interrupted" );
			}
		}	// end: infinite for loop
	}	// end: main
}
company - Sterling Diagnostic Imaging, Inc. , email - ###@###.###
======================================================================


###################### so#3383176 - Thu14May98-15:45 BELLEY ###############3
# java -fullversion
java full version "Solaris_JDK_1.1.5_02"

Bug number 4068618 still occurs on a cleanly installed 128MB Ultra 5
running 2.5.1.  Per the install instructions, I installed patches 103566-25
and 103640-17.

I was monitoring memory usage by simply doing   ls -la /proc/xxx on the pid
of the job.  Left running, this program will CRASH the machine (first, it
reports a SYSSEGV error, and the machine is left in a state that requires a
reboot to clear).

The source code I was using is as follows: (slightly modified from the
reported bug:)

import java.awt.*;
import java.util.*;


public class MemoryLeak7
{
  public static void main( String args[] )
    {
      Frame frame;
      Runtime rt = Runtime.getRuntime();
      for( ;; )
	{
	  for( int i = 0; i < 16; i++ )
	    {
	      frame = new Frame();
	      frame.setSize( 300, 300 );
	      frame.setTitle( "Leaky Frame" );
	      frame.setVisible( true );
	      frame.setVisible( false );
	      frame.dispose();
       	     
	    }
	  rt.gc();
	  System.gc();
	  System.runFinalization();
	  rt.gc();
	  try
	    {
	      System.out.println( "---------- Sleeping ----------" );
	      Thread.currentThread().sleep( 1000 );
	      System.out.println( "------ Finished Sleeping ------" );
	      System.out.println("Total Memory: "+rt.freeMemory());
	    }
	  catch( Exception e )
	    {
	      System.err.println( "Thread interrupted" );
	    }
	} // end: infinite for loop
    } // end: main
}


For what it is worth, we tried this on a system running 2.6, and the same
problem occurs.
###################### 


Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.1.8 FIXED IN: 1.1.6_003 1.1.7b_001 1.1.8 INTEGRATED IN: 1.1.6_003 1.1.7b_001 1.1.8
14-06-2004

EVALUATION I tried this code and there was no memory leak. Perhaps a finalization problem? sheng.liang@Eng 1997-08-05 I was able to reproduce it. There may be other leaks but the problem is that the X11FontMetrics allocates some C heap to keep X font info around but it never frees it. It has a native method called java_awt_Font_dispose which looks like it was intended to do the job. However there is no native method named dispose on java.awt.Font, so of course no one calls it, and even if there was, it's trying to access the pData for java.awt.Font which isn't where the font info is stored. It looks like this was broken by sami's 95/11/27 putback, though it's possible it didn't work even then. I'm handing off to James on this. tom.rodriguez@Eng 1997-08-05 james.mcilree@Eng 1997-11-07 This looks more like a awt problem. ---------------------------------- I have filed a bug report 4199625 to document the bug in win32 side. Note that we cannot simply comment out the "transient private int pData" declaration in src/share/java/java/awt/Font.java because it will break other platforms. Once the win32 platform takes care of font peer disposal in WFontPeer.java, perhaps that is a good time to remove this declaration in Font.java. I have discussed this with David Mendenhall and he agreed that it is a bad idea to expose pData in Font.java (shared java code). patrick.ong@Eng 1998-12-23 Solaris test results before putback into 1.1.8: 1.1.8 build WITHOUT the fontpeer disposal fix & without latest libXM.so.3 but with other AWT memleak fixes: Mon Jan 11 11:00:30 PST 1999 9.0 8152 5544 java ..... Mon Jan 11 11:03:48 PST 1999 21.3 21336 13072 java virtual memory size of java process (2nd number in KB) grew from 8MB to 21MB in 3 minutes. 1.1.8 build WITH the fontpeer disposal fix & without latest libXM.so.3 but with other AWT memleak fixes: Mon Jan 11 11:15:48 PST 1999 9.1 8088 5568 java ..... Mon Jan 11 11:19:14 PST 1999 9.8 9000 6000 java virtual memory size of java process (2nd number in KB) grew from 8MB to <9MB in 3 minutes. Significant improvement. patrick.ong@Eng 1999-01-11 As of today, this bug is only relevant in 1.1.x and is integrated into 1.1.8 and patched in 1.1.6_003 and 1.1.7B_001 patches. In 1.2.2, the bug is addressed by calling pDispose of awt_Font.c from Font.java during finalization. However a regression occured in 1.2 because an array of pointers allocated from XLoadQueryFont() was freed using platform free() instead of XFreeFont(). I pointed this out to the AWT team and the fix was integrated in the latest release of 1.2.2 by Mike Bronson. patrick.ong@Eng 1999-01-25
25-01-1999

SUGGESTED FIX alan.bateman@ireland 1998-06-08 I've eliminated the leak by following Tom Ball suggestion. However I haven't run the JCK signature test to verify that the fix doesn't break the API. Here are the changes for the Solaris Motif implementation :- 1. src/solaris/sun/awt_Font.c :- In awt_GetFontData() replace in two places :- fdata = PDATA(FontData, font); with :- fdata = (struct FontData *) (unhand((Hsun_awt_motif_MFontPeer *)(f->peer))->pData); replace (two places) :- SET_PDATA(font, fdata); with :- unhand((Hsun_awt_motif_MFontPeer *)(f->peer))->pData = (int)fdata; 2. Eliminate the code from java_awt_Font_dispose(), ie :- void java_awt_Font_dispose(struct Hjava_awt_Font *this) { } 3. Add sun_awt_motif_MFontPeer_dispose to replace java_awt_Font_ispose() :- #include "sun_awt_motif_MFontPeer.h" void sun_awt_motif_MFontPeer_dispose (struct Hsun_awt_motif_MFontPeer *this) { struct FontData *fdata; Classsun_awt_motif_MFontPeer *f; if (this == 0) { SignalError(0, JAVAPKG "NullPointerException", 0); return; } AWT_LOCK(); f = unhand(this); fdata = (struct FontData *) (f->pData); if (fdata != 0) { if (unhand(this)->props != NULL) { /* IS_MULTI ? */ int i; for (i = 0; i < fdata->charset_num; i++){ if (fdata->flist[i].load){ XFreeFont(awt_display, fdata->flist[i].xfont); } sysFree(fdata->flist[i].xlfd); sysFree(fdata->flist[i].charset_name); } if (fdata->xfs != NULL){ XFreeFontSet(awt_display, fdata->xfs); } } else XFreeFont(awt_display, fdata->xfont); sysFree(fdata->flist); // this is new sysFree((void*)fdata); f->pData = 0; } AWT_UNLOCK(); } 4. Remove pData from src/share/java/java/awt/Font.java :- /** * Private data. */ //transient private int pData; // commented out 5. Add to src/solaris/sun/sun/awt/motif/MFontPeer.java :- /** * Private data. */ transient private int pData; private native void dispose(); protected void finalize() throws Throwable { dispose(); } tao.ma@Eng 1998-11-17 additional diffs to MFontPeer.java: move the dispose to be called by AWTFinalizer thread to avoid a deadlock: a thread holding AWT_LOCK -> synchronous gc -> wait for "finalize me" notify finalizer thread -> MFontPeer.dispose -> wait for AWT_LOCK *** MFontPeer.java.old Tue Nov 17 11:42:29 1998 --- MFontPeer.java Tue Nov 17 11:52:49 1998 *************** *** 24,31 **** import sun.io.CharToByteConverter; import sun.awt.PlatformFont; import sun.io.CharToByteISO8859_1; ! public class MFontPeer extends PlatformFont { // fix for bug 4068618 /* --- 24,33 ---- import sun.io.CharToByteConverter; import sun.awt.PlatformFont; import sun.io.CharToByteISO8859_1; + import sun.awt.AWTFinalizer; + import sun.awt.AWTFinalizeable; ! public class MFontPeer extends PlatformFont implements AWTFinalizeable { // fix for bug 4068618 /* *************** *** 36,45 **** private native void dispose(); protected void finalize() throws Throwable { ! dispose(); } // end of fix for bug 4068618 /* * XLFD name for XFontSet. */ --- 38,60 ---- private native void dispose(); protected void finalize() throws Throwable { ! AWTFinalizer.addFinalizeable(this); } // end of fix for bug 4068618 + public void doFinalization() { + dispose(); + } + + AWTFinalizeable finalnext; + public void setNextFinalizeable(AWTFinalizeable o) { + finalnext = o; + } + + public AWTFinalizeable getNextFinalizeable() { + return finalnext; + } + /* * XLFD name for XFontSet. */ tao.ma@Eng 1998-11-17 The following is the suggested fix for 1.1.8 already reviewed by David Mendenhall for 1.1.8 putback: ========================================================================= src/solaris/sun/awt_Font.c ========================================================================= *** awt_Font.c Mon Dec 21 07:16:42 1998 --- filemerge.out Mon Dec 21 07:20:14 1998 *************** *** 19,24 **** --- 19,25 ---- #include "java_awt_FontMetrics.h" #include "sun_awt_motif_MToolkit.h" #include "sun_awt_motif_X11FontMetrics.h" + #include "sun_awt_motif_MFontPeer.h" /* bug 4068618 */ #include "java_awt_Dimension.h" #include "multi_font.h" *************** *** 266,272 **** f = unhand(font); ! fdata = PDATA(FontData, font); if (fdata != NULL && fdata->flist != NULL){ return fdata; --- 267,275 ---- f = unhand(font); ! /* bug 4068618 */ ! fdata = (struct FontData *) ! (unhand((Hsun_awt_motif_MFontPeer *)(f->peer))->pData); if (fdata != NULL && fdata->flist != NULL){ return fdata; *************** *** 330,336 **** */ fdata->xfs = NULL; ! SET_PDATA(font, fdata); return fdata; } else { --- 333,340 ---- */ fdata->xfs = NULL; ! /* bug 4068618 */ ! unhand((Hsun_awt_motif_MFontPeer *)(f->peer))->pData = (int)fdata; return fdata; } else { *************** *** 357,363 **** display = XDISPLAY; f = unhand(font); ! fdata = PDATA(FontData,font); if (fdata != NULL && fdata->xfont != NULL) { return fdata; } --- 361,369 ---- display = XDISPLAY; f = unhand(font); ! /* bug 4068618 */ ! fdata = (struct FontData *) ! (unhand((Hsun_awt_motif_MFontPeer *)(f->peer))->pData); if (fdata != NULL && fdata->xfont != NULL) { return fdata; } *************** *** 432,438 **** } } else { fdata->xfont = xfont; ! SET_PDATA(font, fdata); } return fdata; } --- 438,445 ---- } } else { fdata->xfont = xfont; ! /* bug 4068618 */ ! unhand((Hsun_awt_motif_MFontPeer *)(f->peer))->pData = (int)fdata; } return fdata; } *************** *** 501,508 **** void java_awt_Font_dispose(struct Hjava_awt_Font *this) { ! struct FontData *fdata; if (this == 0) { SignalError(0, JAVAPKG "NullPointerException", 0); return; --- 508,523 ---- void java_awt_Font_dispose(struct Hjava_awt_Font *this) { ! /* this code eliminated to fix bug 4068618 */ ! } + /* bug 4068618 */ + void + sun_awt_motif_MFontPeer_dispose (struct Hsun_awt_motif_MFontPeer *this) + { + struct FontData *fdata; + Classsun_awt_motif_MFontPeer *f; + if (this == 0) { SignalError(0, JAVAPKG "NullPointerException", 0); return; *************** *** 509,517 **** } AWT_LOCK(); ! fdata = PDATA(FontData,this); if (fdata != 0) { ! if (IS_MULTI_FONT(this)){ int i; for (i = 0; i < fdata->charset_num; i++){ if (fdata->flist[i].load){ --- 524,534 ---- } AWT_LOCK(); ! f = unhand(this); ! fdata = (struct FontData *) (f->pData); ! if (fdata != 0) { ! if (unhand(this)->props != NULL) { /* IS_MULTI_FONT ? */ int i; for (i = 0; i < fdata->charset_num; i++){ if (fdata->flist[i].load){ *************** *** 527,534 **** } else XFreeFont(awt_display, fdata->xfont); sysFree((void*)fdata); ! SET_PDATA(this,0); } AWT_UNLOCK(); } --- 544,552 ---- } else XFreeFont(awt_display, fdata->xfont); + sysFree(fdata->flist); sysFree((void*)fdata); ! f->pData = 0; } AWT_UNLOCK(); } ============================================================================= src/solaris/sun/sun/awt/motif/MFontPeer.java ============================================================================= *** MFontPeer.java Mon Dec 21 07:25:27 1998 --- filemerge.out Mon Dec 21 07:27:26 1998 *************** *** 16,24 **** import sun.io.CharToByteConverter; import sun.awt.PlatformFont; import sun.io.CharToByteISO8859_1; ! public class MFontPeer extends PlatformFont { /* * XLFD name for XFontSet. */ --- 16,53 ---- import sun.io.CharToByteConverter; import sun.awt.PlatformFont; import sun.io.CharToByteISO8859_1; + import sun.awt.AWTFinalizer; + import sun.awt.AWTFinalizeable; ! public class MFontPeer extends PlatformFont implements AWTFinalizeable { + // fix for bug 4068618 + /* + * Private data + */ + transient private int pData; + + private native void dispose(); + + protected void finalize() throws Throwable { + AWTFinalizer.addFinalizeable(this); + } + + public void doFinalization() { + dispose(); + } + + AWTFinalizeable finalnext; + public void setNextFinalizeable(AWTFinalizeable o) { + finalnext = o; + } + + public AWTFinalizeable getNextFinalizeable() { + return finalnext; + } + + // end of fix for bug 4068618 + /* * XLFD name for XFontSet. */ patrick.ong@Eng 1998-12-23
23-12-1998