[PATCH 0/2] Class- and class loader-local storage (Bug ID #6493635)
David M. Lloyd
david.lloyd at redhat.com
Fri Feb 27 19:44:18 UTC 2009
On 02/27/2009 01:15 PM, Bob Lee wrote:
> On Fri, Feb 27, 2009 at 11:04 AM, David M. Lloyd <david.lloyd at redhat.com> wrote:
>> A couple use cases, off the top of my head:
>>
>> 1) I've got a set of FooBars that associate with Classes; now for whatever
>> reason, I want to change the FooBar that is associated with the Class. The
>> old FooBar is now completely unreferenced; keeping a reference to it is a
>> leak.
>
> What's a FooBar? Use cases should be concrete. :-)
>
>> 2) I've got an application server deployment that provides some kind of
>> service by class, so I stash refs on the ClassLoaders of the Classes for
>> whom the service is provided. I want to undeploy my application, but all
>> those classloaders have strong refs to my deployment. They all have to be
>> cleared or you face a OOM: PermGen after a few redeployments. In this case
>> I'd use a stop() + finalize() on my service which clears them.
>
> Can you provide more detail? It sounds to me like you're saying that
> the service impl classes are in the parent class loader and the server
> (that binds the services) is in the child class loader, but from my
> experience, it's usually the other way around.
It comes back to the whole point of the exercise. Using JBoss Marshalling
as a concrete use case -
WeakHashMap<Class<?>, Externalizer>()
*fails* because Externalizer instances are usually customized to the class
they externalize (which, by the way, could well be a system class). This
means that Externalizer keeps a strong ref to the Class after all.
So we need a map with weak keys -> weak values, and a way to associate a
strong ref from the Class. This covers the case of the Class going away.
But if the deployment containing the Externalizer goes away? It's a leak,
and a big one (it includes the whole classloader of the Externalizer
implementation, not to mention the classloader of Externalizer.class
itself) unless we can remove the reference somehow. Even if you attempt to
work around it by using an intermediate object from the system classloader,
like an Object[1], to hold the references, and you manually keep a Set of
them and clear them all out on redeploy, you've still leaked an Object[1]
on every class or classloader for every redeployment. So it doesn't matter
what classloader the service is bound from, though it can exacerbate the
problem. If I ever want to associate some data with, say, a class from the
system classloader - *even if I make that data be a type from the system
classloader* - that data is now permanent, even when I don't need it
anymore. So if I cause a deployment to happen again, which re-executes the
association, the old data is now leaked.
Your solution puts permanent, uncollectible data on classloaders, no matter
how you slice it. There *has* to be a way to clean it up.
- DML
More information about the core-libs-dev
mailing list