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

class unloading functionality too limited for incremental development

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P4 P4
    • 1.4.0
    • 1.1.5, 1.1.6, 1.2.0, 1.2.1, 1.2.2, 1.3.0
    • hotspot
    • beta2
    • generic, x86
    • generic, windows_95, windows_nt



      Name: tb29552 Date: 06/22/98


      The JDK has some limited support for "unloading"
      classes through making the class, its instances, and
      its ClassLoader become garbage collected.

      I think this current level of support is insufficient
      for building systems that allow incremental
      ("fix and continue") development of Java code.

      This kind of support is important for two reasons.
      One, in the development of many appliations, it
      is necessary to debug and test a small part of
      the code that operates after a lot of "state"
      has been created in the runtime (big data structures,
      interactive state, etc.); restarting the runtime
      again and again for every code change is very slow.
      "Development" may not be a Java programmer, but also
      a system that generates code from a GUI on behalf
      of the user. Another important use of unloading/reloading
      classes is the seamless upgrading of long-running
      servers. Right now, parts of a long-running
      Java server can be upgraded without shutting down
      the server only if they have been architected for upgrading
      by using separate class loaders.

      There are several levels of functionality that can
      be provided that go beyond what Java offers
      right now, with fairly straightforward implementations
      and some history of actual use.

      (1) I should be able to reload code implementing
      the methods of a class if all the method signatures
      and instance variables remain unchanged. This
      would not affect the integrity of the type system.

      (2) There should be some way of reloading a class
      even if its instance variables and/or method
      signatures change. The way this is commonly
      handled is to "rename" the existing loaded
      version of a class and then load the new version
      of the class under the old name.

      "Renaming class A to class B" in the runtime means changing
      its internal state such that it looks as if
      all the files that have been loaded and referred
      to class A had been changed to refer to class B.
      This sounds complicated, but in most runtimes
      for languages like Java, it usually only
      involves altering the name of the class in the
      Class structure; the behavior for natively
      compiled code &c. automatically works out.

      With "rename", class reloading could look
      something like:

      static void unload_by_rename(Class cls) {
         // rename the class to some non-existent
         // class name
         for(int v=1;;v++) {
             try { cls.rename("_"+cls.name+"__"+v); break; }
             catch(ClassRenameFailed e) {}
         }
         // tell the GC that we don't need this
         // class anymore and that it's OK to
         // collect it even if its ClassLoader
         // is still being used
         cls.makeCollectable();
      }
      static void reload(Class cls) {
         // keep around the old name for later reloading
         String old_name = cls.getName();
         // "unload" by renaming
         unload_by_rename(cls);
         // old_name now doesn't refer to a
         // defined class anymore, and this will
         // reload the class file
         Class ncls = Class.forName(old_name);
      }

      The runtime remains internally type consistent.
      Of course, the semantics of the loaded code
      may not always work out as expected, so
      code that used to say
      {A a = (A)Class.forName("A");}
      may result in a runtime type error.
      This means that the sequence:
        -- load classes A, B, and C
        -- rename class B to B0 and load new version of B
      may result in a different internal state than
        -- load classes A, new version of B, and C
      That's potentially surprising, but not really
      a problem given that the "rename" and "reload"
      facilities are low-level facilities that a
      programming environment uses. But it
      indicates that there is something else that
      would be useful for a programing environment:
      an inquiry function to find out which classes
      depend on (or refer to or use) a given class.
      With that, all sorts of "reloading" semantics
      could be implemented:

      static void unload_recursively(Class cls) {
         // class may already have been unloaded,
         // hence the "try ... catch"
         try {unload_by_rename(cls);}
         catch(ClassAlreadyUnloaded e) {return;}
         // recursively "unload"
         Class deps[] = cls.dependentClasses();
         for(int i=0;i<deps.length;i++)
            unload_recursively(deps[i]);
      }
         
      There are several languages and systems
      (SML, Erlang, CommonLisp, Smalltalk, ...) that
      have addressed incremental development and
      dynamic redefinitions, some of them even in
      the presence of static typing. I think
      it's well worth looking into them more carefully
      and see whether similar functionality can't
      be provided as part of standard Java.
      (Review ID: 34090)
      ======================================================================

      Name: krT82822 Date: 10/19/99


      I've been fighting a very mysterious java.lang.IllegalAccessError
      between an outer class trying to create an inner class. Know I
      know why it happend on every VM I got
      (Linux Blackdown, Linux IBM, Windows JDK, 1.1 and 1.2): The
      outer class was loaden by another class loader than the inner
      class was. Is this a reason for throwing a
      java.lang.IllegalAccessError?

      Because RFE #4151172 has not yet been implemented, I
      worked around the class-unloading-problem by giving each loaded
      class an individual class loader. If I want a class to completetely
      disappear, I drop all references to its very own class loader,
      force garbage collection and hope that this class was not used
      by any other current class in the system. This worked pretty
      well, until I tried to use inner classes.

      What behaviour of implementing this feature do you suggest
      for current Java releases?
      (Review ID: 96654)
      ======================================================================

            rfield Robert Field (Inactive)
            tbell Tim Bell
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: