Speaks for itself ... --John Keiser -----Original Message----- From: Dave Makower [mailto:[EMAIL PROTECTED]] Sent: Wednesday, July 22, 1998 11:02 AM To: [EMAIL PROTECTED] Subject: Weak references in pre-1.2 JDK Here are a couple of snippets from Apple's MRJ-Dev mailing list, indicating that weak references, though unsupported before JDK 1.2, have been a part of the JDK for quite a while... Jens Alfke <[EMAIL PROTECTED]> wrote: >JDK 1.1 doesn't _publicly_ support weak references, but they've been >there (in the unsupported sun.misc package) since 1.0 as far as I know. >They're definitely in all versions of MRJ. > >I'm not sure why they're not in an official package; perhaps there wasn't >agreement at Javasoft about whether the API was correct. They are >certainly used internally by Java itself (Image pixmaps are >weak-referenced so they go away when memory gets low) and by some >Javasoft apps such as HotJava, so we know that they work. > >The basic weak-references classes are sun.misc.Ref and sun.misc.Cache. >Ref simply holds a single weak reference to an object, which can be get >and set. Methods are: > > >/* returns the thing referred to, reconstituting it if it's been flushed, >and bumps the LRU count to mark it as recently used. */ >Object get( ); > >/* sets the ref to the thing */ >void setThing( Object thing ); > >/* returns the current contents of the ref, which may have been null'ed >out */ >Object check( ); > >/* nulls out the reference */ >void flush( ); > >/* should reconstitute the ref, returning a new object -- called by get >when the thing is requested again after it's been flushed */ >abstract Object reconstitute( ); > > >(That was _not_ copied directly from the sources; it's my interpretation. >You can easily look at the API yourself using Class Wrangler.) > >Since reconstitute is abstract, you have to subclass Ref to use it. You >can make a "smart" ref whose reconstitute method recreates the data that >got GC'd (e.g. by reloading image pixels) or you can make a dumb one >whose reconstitute just returns null, in which case the caller needs to >check for a null value from get() and take appropriate action. > >In my experience, Refs are important for complex persistent data >structures where you want to cache loaded data in memory, but not have >the memory usage grow monotonically as more data gets loaded. > >The API in JDK 1.2 is pretty similar, although they've added a whole >class hierarchy to make things more generalized, and moved everything to >java.lang. I'm glad they're finally making this public... > >--Jens Jon Pugh <[EMAIL PROTECTED]> wrote: >Jens pointed out that there are some >undocumented sun classes which implement this stuff in 1.1. I wrote a >little test app to check it out. It consists of a Gizmo class, a WeakGizmo >class and a main which creates a bunch of them and then sees if they're >still referenced. > >Basically, the crux is the use of the sun.misc.Ref and sun.misc.Cache >classes. You extend Ref to get a weak referenced object, implementing the >reconstitute method to either return null or a newly created object if you >want your purged references to disappear or reappear. The WeakGizmo >rerecreates objects as "Gazmo"s in the example below. Returning null is >interesting too. > >There's a lot of options to play with in main, but the gist seems to be >that weak references work fine, but it takes a long time for the garbage >collector to kick in when you are doing something this mundane. I found >that it wouldn't start purging references until 10,000 objects or more were >allocated. > >The Cache class works as a weak hash table, keeping a key and forgetting >the object if it gets purged. > >Beyond that there's not much to it. It seems to work fine. > >Jon Here's Jon's code, without the '>' characters at the start of every line, so you can cut and paste it, if you're curious: Gizmo.java: public class Gizmo { String name; Gizmo( String t ) { name = t; } } WeakGizmo.java: import sun.misc.Ref; public class WeakGizmo extends Ref { int gizmoNumber; public WeakGizmo( Gizmo g ) { setThing( g ); gizmoNumber = ( new Integer( g.name.substring( 6 ) )).intValue(); } public Gizmo getGizmo() { return (Gizmo) get(); } public Object reconstitute() { return new Gizmo( "Gazmo " + gizmoNumber ); } } TrivialApplication: /* Trivial application that tests weak references - Jon Pugh 5/98 */ import java.util.*; import java.text.*; import sun.misc.*; public class TrivialApplication { static final boolean SAVEWEAK = false; static final boolean PRINTNAMES = false; static final boolean COLLECTGARBAGE = true; static final int COUNT = 10000; static final int SAVE = COUNT / 2; static final String NAME = "Gizmo "; public static void main(String args[]) { int i, nullCount, gazmos; Cache c = new Cache(); Vector v = new Vector( SAVE ); boolean saveWeak = SAVEWEAK; boolean printNames = PRINTNAMES; boolean collectGarbage = COLLECTGARBAGE; int count = COUNT; int save = SAVE; String t; if ( (t = System.getProperty( "SAVEWEAK" )) != null ) { saveWeak = ( new Boolean( t ) ).booleanValue(); } if ( (t = System.getProperty( "PRINTNAMES" )) != null ) { printNames = ( new Boolean( t ) ).booleanValue(); } if ( (t = System.getProperty( "COLLECTGARBAGE" )) != null ) { collectGarbage = ( new Boolean( t ) ).booleanValue(); } if ( (t = System.getProperty( "COUNT" )) != null ) { count = ( new Integer( t ) ).intValue(); } if ( (t = System.getProperty( "SAVE" )) != null ) { save = ( new Integer( t ) ).intValue(); } System.out.println( DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT ).format( new Date() ) ); System.out.println( "Making " + count + " gizmos and saving " + ( saveWeak ? "(weakly) " : "" ) + save + " of them." ); for ( i = 0; i < count; i++ ) { Gizmo g = new Gizmo( NAME + i ); c.put( g.name, g ); if ( i < save ) { if ( !saveWeak ) v.addElement( g ); else v.addElement( new WeakGizmo( g ) ); } if ( printNames ) System.out.println( g.name ); } System.out.println( "Done making gizmos" ); if ( collectGarbage ) { System.out.println( "Running gc" ); System.gc(); } System.out.println( "Examining gizmo cache" ); System.out.println( "Gizmos in cache before: " + c.size() ); for ( Enumeration e = c.elements(); e.hasMoreElements(); ) { Gizmo g = (Gizmo) e.nextElement(); if ( printNames ) System.out.println( g.name ); } System.out.println( "Gizmos in cache after: " + c.size() ); nullCount = 0; gazmos = 0; System.out.println( "Examining gizmo references" ); for ( Enumeration e = v.elements(); e.hasMoreElements(); ) { //Gizmo g = ( (WeakGizmo) e.nextElement() ).getGizmo(); Gizmo g; if ( !saveWeak ) g = (Gizmo) e.nextElement(); else g = ( (WeakGizmo) e.nextElement() ).getGizmo(); if ( g == null ) ++nullCount; else { if ( g.name.startsWith( "Gazmo " ) ) ++gazmos; if ( printNames ) System.out.print( g.name + ", " ); } } if ( printNames ) System.out.println(); System.out.println( "Null gizmos: " + nullCount + " ( " + (save - nullCount) + " )" ); System.out.println( "Gazmos: " + gazmos ); System.out.println( "Gizmos in cache now: " + c.size() ); System.out.println( DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT ).format( new Date() ) ); } } +-------------------+-----------------------+-------------------------+ | Dave Makower | [EMAIL PROTECTED] | Internet Technologist | +-------------------+-----------------------+-------------------------+ | Co-author of "Java Programming Basics" (Henry Holt/MIS:Press) | | http://www.pencom.com/javabasics/ | +----------------------------------+----------------------------------+ | Pencom Web Works | (212) 513-7777 voice | | 40 Fulton St. | (212) 513-1014 fax | | New York, NY 10038 | http://www.pencom.com/ | +----------------------------------+----------------------------------+

