Unloading classes

Jeff Sturm jsturm@one-point.com
Sun Nov 3 17:16:00 GMT 2002


On 3 Nov 2002, Anthony Green wrote:
> I recently noticed that we don't unload interpreted classes properly.
> The following test program loops around, dynamically creating a class
> loader and class on each iteration.  The heap should, in theory, stop
> growing at some point - but it doesn't.

I'd seen the opposite, i.e. classes can be GC'ed prematurely:

http://gcc.gnu.org/ml/java/2002-07/msg00043.html

> I believe the problem is with initiated_classes and loaded_classes, in
> natClassLoader.cc.  It seems like we'll have to do some of the same tricks
> we pull in natReference.c in order to turn these into "weak" reference data
> structures (and eliminate Class.next).  Any other ideas?

Also, a classloader must keep strong references to its loaded classes.

You can call GC_exclude_static_roots for the loaded_classes array, but the
collector will still follow the Class.next pointer for compiled classes
because they appear in static roots.  (And for other reasons I'd also be
happy to eliminate Class.next anyway.)

Possibly the easiest thing is to not _Jv_RegisterClass interpreted classes
at all.  I hacked together the patch below some time ago, but hadn't
gotten around to submitting it because I'm not convinced it doesn't break
classloading in some subtle way.

Index: defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.29
diff -u -p -r1.29 defineclass.cc
--- defineclass.cc	24 Jun 2002 20:38:45 -0000	1.29
+++ defineclass.cc	4 Nov 2002 01:08:26 -0000
@@ -908,11 +908,6 @@ _Jv_ClassReader::handleClassBegin

   def->state = JV_STATE_PRELOADING;

-  {
-    JvSynchronize sync (&java::lang::Class::class$);
-    _Jv_RegisterClass (def);
-  }
-
   if (super_class != 0)
     {
       // Load the superclass.
Index: java/lang/Class.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.java,v
retrieving revision 1.14
diff -u -p -r1.14 Class.java
--- java/lang/Class.java	3 Sep 2002 21:33:46 -0000	1.14
+++ java/lang/Class.java	4 Nov 2002 01:08:31 -0000
@@ -345,9 +345,6 @@ public final class Class implements Seri
   // Initialize the class.
   private native void initializeClass ();

-  // finalization
-  protected native void finalize ();
-
   /**
    * Strip the last portion of the name (after the last dot).
    *
Index: java/lang/ClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/ClassLoader.java,v
retrieving revision 1.18
diff -u -p -r1.18 ClassLoader.java
--- java/lang/ClassLoader.java	7 Aug 2002 05:28:24 -0000	1.18
+++ java/lang/ClassLoader.java	4 Nov 2002 01:08:31 -0000
@@ -74,6 +74,7 @@ public abstract class ClassLoader
   Map classAssertionStatus;

   private ClassLoader parent;
+  private HashMap loadedClasses = new HashMap();
   private HashMap definedPackages = new HashMap();

   public final ClassLoader getParent ()
@@ -368,9 +369,10 @@ public abstract class ClassLoader
       // Since we're calling into native code here,
       // we better make sure that any generated
       // exception is to spec!
+      Class cl = defineClass0 (name, data, off, len, protectionDomain);

-      return defineClass0 (name, data, off, len, protectionDomain);
-
+      loadedClasses.put (name, cl);
+      return cl;
     } catch (LinkageError x) {
       throw x;		// rethrow

Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.53
diff -u -p -r1.53 natClass.cc
--- java/lang/natClass.cc	3 Sep 2002 21:33:46 -0000	1.53
+++ java/lang/natClass.cc	4 Nov 2002 01:08:32 -0000
@@ -692,15 +692,6 @@ java::lang::Class::newInstance (void)
   return r;
 }

-void
-java::lang::Class::finalize (void)
-{
-#ifdef INTERPRETER
-  JvAssert (_Jv_IsInterpretedClass (this));
-  _Jv_UnregisterClass (this);
-#endif
-}
-
 // This implements the initialization process for a class.  From Spec
 // section 12.4.2.
 void
Index: java/lang/natClassLoader.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClassLoader.cc,v
retrieving revision 1.49
diff -u -p -r1.49 natClassLoader.cc
--- java/lang/natClassLoader.cc	25 Jun 2002 05:29:20 -0000	1.49
+++ java/lang/natClassLoader.cc	4 Nov 2002 01:08:33 -0000
@@ -40,6 +40,7 @@ details.  */
 #include <java/lang/StringBuffer.h>
 #include <java/io/Serializable.h>
 #include <java/lang/Cloneable.h>
+#include <java/util/HashMap.h>

 /////////// java.lang.ClassLoader native methods ////////////

@@ -84,8 +85,6 @@ java::lang::ClassLoader::defineClass0 (j
       klass->state = JV_STATE_ERROR;
       klass->notifyAll ();

-      _Jv_UnregisterClass (klass);
-
       _Jv_MonitorExit (klass);

       // FIXME: Here we may want to test that EX does
@@ -226,7 +225,11 @@ gnu::gcj::runtime::VMClassLoader::findCl
 jclass
 java::lang::ClassLoader::findLoadedClass (jstring name)
 {
-  return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this);
+  jclass cl = (jclass) loadedClasses->get (name);
+
+  if (!cl)
+    cl = _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this);
+  return cl;
 }

 /** This function does class-preparation for compiled classes.



More information about the Java mailing list