A few Javassist proxy patches
struberg Mar 2, 2010 4:35 AMHi!
I'm working on Apache OpenWebbeans and we use javassist - so first of all thanks for providing it!
I found a few issues which are mainly based on the way javassist got used in many projects, which caused loss of permgenspace with every invocation. I tried to address this with a few patches.
The problem is caused by the current javassist usage pattern of calling ProxyFactory.createClass().newInstance() which currently (due to the broken cache), always creates a new class for the proxy. And once this class gets classloaded, you cannot easily get rid of it from the ClassLoaders class map. In the worst case the generated proxy class gets registered in the SystemClassLoader and can never get freed again. Another problem is that setting the default method handler with ProxyFactore.setMethodHandler() will store this MethodHandler in a static field, thus the class will hold a reference to this MethodHandler - even if it is not used anymore. Thus the MethodHandler (and all the instances it references) imo can never get garbage collected.
There were also a few problems with deserialization, mainly because it did drop the assigned MehodHandler and used the DefaultMethodHandler instead. I added new bytecode to support MethodHandler serialization along with the proxyInstance.
To understand my need: instead of creating a fresh proxyClass every time, I switched OWB to use the following pattern
1.) ProxyFactory.useCache = false; since the current implementation fo the internal class cache imo inherently creates mem losses
2.) create the ProxyFactory only once and cache this class in our own code:
2.a) ProxyFactory pf = new ProxyFactory()
2.b) pf.setInterfaces(...);
2.c) pf.setSuperclass(...);
2.d) Class proxyClass = pf.creatClass();
3.) create a new proxy instance with it's own MethodHandler by always only using the same cached proxy Class for a certain original class
Object proxyInstance = proxyClass.newInstance(); +
((ProxyObject)proxyInstance).setHandler(new BeanMethodHandler(beaninfo));
I didn't really need the MethodFilter in my use cases, so we need think about where this fits into the picture.
Most foundings are explained in my patches available at github
http://github.com/struberg/javassist
Those patches are tested with OpenWebBeans and Weld (thanks to David R. Allen), but I'm sure there is still room for improvement
One of the areas I'm not 100% sure is deserialization on another VM which may already contain other proxy classes of that kind (with different javassist name). I now check if the interfaces and the superclass is the same if I found a javassist proxyClass with Class.forName on deserialization, maybe there is something missing still.
This szenario mainly may concern replication in big clusters, and the behaviour of the patched version is of course heavily improved at least.
Oh yes, we should really cleanup the pom.xml!
I can volunteer with all the maven stuff too if needed.
txs and LieGrue,
strub