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/         |
+----------------------------------+----------------------------------+


Reply via email to