Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4485942

(ref) Cleared SoftReference not added to ReferenceQueue if get() is called

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 1.3.1
    • core-libs
    • generic
    • generic



      Name: boT120536 Date: 07/30/2001


      java version "1.3.1"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
      Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)


      Normally all soft references cleared by the garbage collector are added
      to the reference queue the reference was created with (if any). But if
      a program happens to call SoftReference.get() after the reference has
      been cleared, but before it has been added to the reference queue it
      will never be added to the reference queue.

      The program below illustrates the problem. The test class is a simplified
      version of a cache implementation using soft references to allow the garbage
      collector to remove cache entries.

      The test code keeps track of the number of expected entries in the cache
      by counting the number of entries added and removed.

      When running the program, the first output column is the difference
      between the actual number of entries in the cache and the expected number,
      i.e. when the first column is non-zero something is wrong.

      The last column shows the number of times SoftReference.get() has been
      called and returned null. In my tests, the size mismatch (the first column)
      always is the same as the number of null returns from get() (but with the
      opposite sign).

      Note that the program might need to run for a while for the problem to
      show up, the last output column must be non-zero for the necessary
      conditions to be present. Since the garbage collector is involved,
      adjusting the maximum memory allowed may speed things up. The problem
      seems to happen most frequently when the garbage collector clears
      large numbers of soft references.

      If the program is run with one or more arguments, the bug workaround
      is enabled.

      ----------[SoftRefTest.java]----------
      import java.lang.ref.ReferenceQueue;
      import java.lang.ref.SoftReference;
      import java.util.HashMap;
      import java.util.Random;


      public class SoftRefTest
      {
          HashMap map;
          ReferenceQueue refQueue;
          Random random;
          int numRemoved;
          int numNullGets;
          boolean doWorkAround;

          public SoftRefTest(boolean doWorkAround)
          {
      map = new HashMap();
      refQueue = new ReferenceQueue();
      random = new java.util.Random();
      numRemoved = 0;
      numNullGets = 0;
      this.doWorkAround = doWorkAround;
          }

          public Object get(Object key)
          {
      removeBroken();
      MySoftRef ref = (MySoftRef) map.get(key);
      if (ref != null) {
      Object result = ref.get();
      if (result == null) {
      if (doWorkAround) {
      // this object has been cleared by the garbage
      // collector but will _not_ be added to the
      // reference queue. do workaround.
      map.remove(key);
      numRemoved++;
      }
      numNullGets++;
      }
      return result;
      }
      else {
      return null;
      }
          }

          public void put(Object key, Object value)
          {
      removeBroken();
      map.put(key, new MySoftRef(key, value, refQueue));
          }

          protected void removeBroken()
          {
              MySoftRef broken;
              while ((broken = (MySoftRef) refQueue.poll()) != null) {
      Object key = broken.key;
      if (map.get(key) != null) {
      map.remove(key);
      numRemoved++;
      }
              }
          }

          class MySoftRef extends SoftReference
          {
      public Object key;

      public MySoftRef(Object key, Object value, ReferenceQueue queue)
              {
                  super(value, queue);
                  this.key = key;
              }
          }


          public void test()
          {
      int numAdded = 0;

      for (int n = 0; n < 1000; n++) {
      for (int i = 0; i < 1000; i++) {
      Integer r = new Integer(random.nextInt(100000));
                      if (get(r) == null) {
                          // add ~1 Kbyte objects
      put(r, new Object[256]);
      numAdded++;
                      }
        }

      int size = map.size();
      int expectedSize = numAdded - numRemoved;
      if (n % 50 == 0)
      System.out.println("\nsize-expectedSize size numAdded " +
      "numRemoved numNullGets\n");
      System.out.println("" + (size - expectedSize) + " " + size + " " +
      numAdded + " " + numRemoved + " " + numNullGets);

      try {
      Thread.sleep(100);
      }
      catch (InterruptedException e) {
      }
      }
          }

          public static void main(String[] args)
          {
      SoftRefTest test = new SoftRefTest(args.length > 0);
      test.test();
          }
      }
      ----------[end of SoftRefTest.java]----------
      (Review ID: 128187)
      ======================================================================

            kbarrett Kim Barrett
            bonealsunw Bret O'neal (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: