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

JNI weak references cannot avoid resurrecting weakly referenced objects.

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 1.4.0
    • hotspot
    • x86
    • windows_2000



      Name: jk109818 Date: 01/23/2002


      FULL PRODUCT VERSION :
      java version "1.4.0-rc"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-rc-b91)
      Java HotSpot(TM) Client VM (build 1.4.0-rc-b91, mixed mode)

      FULL OPERATING SYSTEM VERSION :

      Microsoft Windows 2000 [Version 5.00.2195]



      A DESCRIPTION OF THE PROBLEM :
      ** Note: This is a resubmission that repeats one made about
      a year ago but never made it to the bug database. Since
      then Jeff Kesselman from Sun has confirmed that this is in
      fact a bug so please take it seriously. **

      ****** Overview *******

      Note: This text uses garbage collector terms from the book:
      Java platform
      performance, appendix A, which is available on-line from
      Sun.

      The main issue that I wish to address is the fact that is
      you access an
      object via a weak reference in native code (with JNI) then
      you
      have no way of telling whether the finalization process has
      begun and
      cannot be stopped.

      I suggest the JNI function NewLocalRef(env,obj) is changed
      such that
      using it on a weak reference obj it returns only non-null
      if the object
      has not yet been collected, unlike now where it return non-
      null until the
      object is finally reclaimed. This change is an
      implementation change that can
      be changed without changing the specification.

      I have not used the java.lang.ref.* objects but as far as I
      understand
      from the documentation an object is no longer weakly
      reachable when
      it has been collected. After this it might be finalized at
      any time. It
      therefore makes sense to avoid the use of weak references
      that
      points to objects not weakly referenced. In other words, by
      making the change I
      suggest you make the system more consistant by avoiding
      that they user
      references phantom referenced objects using JNI weak
      references.

      ---------------

      *** The problem in more detail ***

      Currently we have only one way to use an object referenced
      with a weak reference in JNI:

      jobject jobj = env->NewLocalRef(obj); // obj is a weak
      reference.
      if (!env->IsSameObject(jobj,NULL))
        ... use jobj ...

      We make a strong reference in the call to NewLocalRef() to
      avoid the case when
      the weakly referenced object is collected after the call to
      IsSameObject() and
      before its use. (can happen if a asynchronous garbage
      collector is used)

      In the above situation NewLocalRef() returns only NULL when
      the object
      has been reclaimed by the system. This means that we might
      make a strong
      reference to an object that has already been finalized or
      are queued for
      finalization. In fact, it might be finalized at this
      instant if a VM that
      runs finalizers in seperate threads are used.

      In my case I have weak references to objects that has
      external resources
      that must reclaimed upon finalization. The object has no
      external resources
      after finalization and should therefore not be used. It is
      *not* enough
      to set some variable in the finalize() method to say that
      the external
      resources are released - because if the finalizer thread is
      interrupted
      in its first line of finalize() this value is not set.





      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      See source code below.



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      I would expect that a reference could not access an object
      that has finalized. This is what occurs in the given source
      code sample.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Upon execution the sample program writes (only the last part is shown):

      ...
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      Error! Object already finalized.

      This bug can be reproduced rarely.

      ---------- BEGIN SOURCE ----------
      ******* Source of example *************

      The full source of an example that shows how this goes wrong:
      (This was detected in version 1.2.2 of the JDK and has been tested with each
      version since then until finally 1.4.0 rc. It was present in all versions. It
      has been tested on both Windows 98 and Windows 2000. I used Microsoft Visual C++
      6.0 to compile the native part)

      This simple program needs to be run for a while until the timing
      of the use of the weak reference is right. On my computer it
      happens after 120 iterations or 105 iterations depending on the system. If you
      turn on the commented call to
      System.gc() it takes so long that I lost patience, but this is just a hack to
      postpone that the program crashes.

      Bad.java:
      ============

      class Bad
      {
        boolean legal = true;

        protected void finalize()
        {
          legal = false;
          // external clean-up goes here. The use of the
          // object after this point is an error.
        }

        public static void main(String[] args)
        {
          System.loadLibrary("bug");

          int count = 1;
          while (true)
          {
            //System.gc(); // Uncomment this to keep garbage collector
                           // up to date. Avoids problem in most cases.
            System.out.println(count);
            generateReferences(count);
            retrieveReferences(count);
            count++;
          }
        }

        public static void generateReferences(int count)
        {
          for (int i=0;i<count;i++)
          {
            Bad object = new Bad();
            n_storeReference(object);
          }
        }
        native static void n_storeReference(Bad object);

        public static void retrieveReferences(int count)
        {
          for (int i=0;i<count;i++)
          {
            Bad object = n_retrieveReference();

            if (object!=null && !object.legal)
            {
              System.out.println("Error! Object already finalized.");
              System.exit(1);
            }

            // This is where we would use the object. If it is
            // finalized then the external data is illegal.
          }
        }
        native static Bad n_retrieveReference();
      }


      And the C++ files native.cpp that becomes bug.dll:
      ===================================

      #include "Bad.h"

      #include <list>

      std::list<jobject> objectlist;

      JNIEXPORT void JNICALL Java_Bad_n_1storeReference
        (JNIEnv *env, jclass, jobject jobj)
      {
        jobject o = env->NewWeakGlobalRef(jobj);
        objectlist.push_front(o);
      }


      JNIEXPORT jobject JNICALL Java_Bad_n_1retrieveReference
        (JNIEnv *env, jclass)
      {
        if(!objectlist.empty())
        {
          jobject jobj = env->NewLocalRef(objectlist.back());
          objectlist.pop_back();
          if (!env->IsSameObject(jobj,NULL))
            return jobj;
        }
        return NULL;
      }

      ---------- END SOURCE ----------

      CUSTOMER WORKAROUND :
      A temporary, not fully satisfactory, workaround is to delete
      all weak references to an object from its finalizer. It may
      still go wrong
      but chances are we will not use a that weak references to
      an object
      that has been finalized.
      (Review ID: 138679)
      ======================================================================

            foliversunw Fred Oliver (Inactive)
            jkimsunw Jeffrey Kim (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: