6232010 was one of the related bugs, although it was specifically about pinned 
stream subclasses, as opposed to serializable classes in the class descriptor 
cache-- it and the class descriptor cache were fixed at the same time, though, 
along with 5056445.

I highly doubt that those fixes have been backported to CDC, because they 
depended on java.util.concurrent.ConcurrentHashMap, which was introduced in 
Java SE 5.0.  As I said in my previous message, though, even without those 
fixes, with ongoing activity, class descriptor cache entries would eventually 
get cleared.

-- Peter


On Apr 12, 2010, at 5:39 PM, Peter Firmstone wrote:

> Awesome thanks, I found the bug database record.
> 
> http://bugs.sun.com/view_bug.do?bug_id=6232010
> 
> I'll have to see if I can track down the CDC source code and see if it too 
> has the fix.
> 
> For what I'd like to do with ClassLoaders, this bug would have been a show 
> stopper.
> 
> You can just imagine my thoughts, stumbling across it, while theorising about 
> how to reduce duplication of class files, by sharing code between services 
> for services utilising common packages.  I'd also like to return results from 
> lookup as a stream, ordered by common bytecode, so the local jvm garbage 
> collects unwanted results during stream inspection, to avoid a memory 
> explosion.
> 
> Cheers,
> 
> Peter.
> 
> Gregg Wonderly wrote:
>> It was my understanding that this issue had been solved as well.
>> 
>> Gregg Wonderly
>> 
>> Christopher Dolan wrote:
>>> This is news to me.  Looking at the JDK 1.5 source code, I can see that
>>> ObjectStreamClass$Caches uses weak references for the classes.  So
>>> either this is a solved problem as of 1.5, or there's something
>>> non-obvious in the implementation that I've overlooked.
>>> 
>>> Chris
>>> 
>>> -----Original Message-----
>>> From: Peter Firmstone [mailto:[email protected]] Sent: Saturday, April 10, 
>>> 2010 8:25 PM
>>> To: [email protected]
>>> Subject: ClassLoader and Class Garbage Collection issues with
>>> Serialization.
>>> 
>>> I have stumbled across a troubling problem with Serialization relating to 
>>> Garbage Collection of Classes and ClassLoaders and was hoping someone
>>> 
>>> might be able to shed some light on the issue.
>>> 
>>> Is it really true that the more objects you distribute, the greater your
>>> 
>>> memory consumption because Class files and ClassLoaders cannot be garbage 
>>> collected?
>>> 
>>> Regards,
>>> 
>>> Peter.
>>> 
>>> The issue can be found here:
>>> http://www.ibm.com/developerworks/java/library/j-dclp3/index.html
>>> 
>>> And here's the relevant information, pasted from the link:
>>> 
>>> 
>>>  Problems related to garbage collection and serialization
>>> 
>>> The garbage collector interacts closely with the class loader. Among other 
>>> things, the collector examines the class loader data structures to
>>> 
>>> determine which classes are /live/ -- that is, are not garbage collectable. 
>>> This can often lead to some unexpected problems.
>>> 
>>> Figure 2 illustrates a situation where serialization affects the garbage
>>> 
>>> collection (GC) of classes and a class loader in an unexpected way:
>>> 
>>> 
>>>    *Figure 2. Serialization example*
>>> 
>>> Serialization example
>>> 
>>> In this example, |SerializationTest| instantiates a |URLClassLoader|, 
>>> called |loader|. After loading |SerializationClass|, the class loader is
>>> 
>>> dereferenced. The expectation is that this will allow the classes loaded
>>> 
>>> by it to be garbage collected. The code for these classes is illustrated
>>> 
>>> in Listings 9 and 10:
>>> 
>>> 
>>> *Listing 9. SerializationTest.java*
>>> 
>>> import java.net.MalformedURLException;
>>> import java.net.URL;
>>> import java.net.URLClassLoader;
>>> 
>>> public class SerializationTest extends ClassLoader {
>>> 
>>>   public static void main(String args[]) {
>>>      try {
>>>         URLClassLoader loader = new URLClassLoader(new URL[] { new URL(
>>>               "file://C:/CL_Article/Serialization/dir1/") });
>>>         System.out.println("Loading SerializationClass");
>>>         Class c = loader.loadClass("SerializationClass");
>>>         System.out.println("Creating an instance of
>>> SerializationClass");
>>>         c.newInstance();
>>>         System.out.println("Dereferencing the class loader");
>>>         c = null;
>>>         loader = null;
>>>                  System.out.println("Running GC...");
>>>         System.gc();
>>>         System.out.println("Triggering a Javadump");
>>>         com.ibm.jvm.Dump.JavaDump();
>>>               } catch (MalformedURLException e) {
>>>         e.printStackTrace();
>>>      } catch (InstantiationException e) {
>>>         e.printStackTrace();
>>>      } catch (IllegalAccessException e) {
>>>         e.printStackTrace();
>>>      } catch (ClassNotFoundException e) {
>>>         e.printStackTrace();
>>>      }
>>>   }
>>> }
>>> 
>>> 
>>> 
>>> *Listing 10. SerializationClass.java*
>>> 
>>> import java.io.File;
>>> import java.io.FileOutputStream;
>>> import java.io.ObjectOutputStream;
>>> import java.io.Serializable;
>>> 
>>> public class SerializationClass implements Serializable {
>>> 
>>>    private static final long serialVersionUID = 5024741671582526226L;
>>> 
>>>    public SerializationClass() {
>>>        try {
>>>            File file = new
>>> File("C:/CL_Article/Serialization/test.txt");
>>>            FileOutputStream fos = new FileOutputStream(file);
>>>            ObjectOutputStream oos = new ObjectOutputStream(fos);
>>>            oos.writeObject(this);
>>>            oos.reset();
>>>            oos.close();
>>>            fos.close();
>>>            oos = null;
>>>            fos = null;
>>>            file = null;
>>>        } catch (Exception e) {
>>>            e.printStackTrace();
>>>        }
>>>    }
>>> }
>>> 
>>> 
>>> Using a Javadump, it is possible to discover whether the class loader has 
>>> been garbage collected. (See the first article in this series for more on 
>>> using Javadump.) If the following section appears in the list of
>>> 
>>> class loaders, then it has not been collected:
>>> 
>>> ------a- Loader java/net/URLClassLoader(0x44DC6DE0), Shadow 0x00ADB6D8,
>>>        Parent sun/misc/Launcher$AppClassLoader(0x00ADB7B0)         Number 
>>> of loaded classes 1         Number of cached classes 11              
>>> Allocation used for loaded classes 1              Package owner 0x00ADB6D8
>>>     
>>> Though dereferencing a user-defined class loader seems like a way to ensure 
>>> that the classes are garbage collected, this is not actually the case. In 
>>> the previous example, the problem stems from the use of 
>>> |java.io.ObjectOutputStream.writeObject(Object obj)| and its implications 
>>> on GC.
>>> 
>>> When |writeObject()| is invoked (to serialize |SerializationClass|), a 
>>> reference to this class object is passed internally to |ObjectStreamClass| 
>>> and stored in a lookup table (that is, in an internal cache). This 
>>> reference is kept to speed up future serialization
>>> 
>>> of the same class.
>>> 
>>> When the class loader is dereferenced, the classes that it loaded are not 
>>> garbage collectable. This is because there is a live reference to the 
>>> |SerializationClass| class from the |ObjectStreamClass| lookup table. 
>>> |ObjectStreamClass| is a primordial class and therefore is never garbage 
>>> collected. The lookup table is referenced from a static field in
>>> 
>>> |ObjectStreamClass| and is kept in the class itself rather than in an 
>>> instance of it. As a result, the reference to |SerializationClass| exists 
>>> for the lifetime of the JVM, and the class thus cannot be garbage
>>> 
>>> collected. Importantly, the |SerializationClass| class has a reference to 
>>> its defining class loader, and so it cannot be completely dereferenced 
>>> either.
>>> 
>>> To avoid this problem, any classes that are to be serialized should be 
>>> loaded by a class loader that does not need to be garbage collected -- by 
>>> the system class loader, for example.
>>> 
>>> 
>>> 
>> 
>> 
> 

Reply via email to