JDK-4151172 : class unloading functionality too limited for incremental development
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 1.1.5,1.1.6,1.2.0,1.2.1,1.2.2,1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,windows_95,windows_nt
  • CPU: generic,x86
  • Submitted: 1998-06-22
  • Updated: 2012-10-13
  • Resolved: 2001-07-31
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.0 beta2Fixed
Related Reports
Duplicate :  
Relates :  
Description

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)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin-beta FIXED IN: merlin-beta2 INTEGRATED IN: merlin-beta2
14-06-2004

WORK AROUND Name: krT82822 Date: 10/19/99 Do not use individual class loaders or implement RFE #4151172. (Review ID: 96654) ======================================================================
11-06-2004

EVALUATION This work is planned for Merlin and is needed as the underpinnings of: 4287595: JPDA Class File Redefinition Current thinking is both a JVM and JVMDI interface. robert.field@Eng 2000-04-19 4287595 is now integrated in Merlin. This provides out of process access to class reloading. There is no JVM interface or other in-process access. However, both applications mentioned for this functionality are best addressed by out of process means (debugging and updating servers). The debugging architecture (JPDA) is out of process and this functionality is avilable at all levels. Servers are probably more safely updated using class loader means (or server switching) however there will be cases where this will not work. Server updating could, in theory, be done using JPDA. At this time there is a significant performance penalty for running under debugger control (but that is another issue). I am closing this bug as integrated in Merlin beta refresh. is avilable robert.field@Eng 2001-07-30
30-07-2001