1 2 Previous Next 25 Replies Latest reply on Nov 4, 2009 12:21 PM by jaikiran Go to original post
      • 15. Re: EJB3 Classloader Leak (EJBTHREE-1442)
        ron_sigal

        I just noticed that, in a fit of housekeeping, it looks I changed ServerThread from version 2.2 to 2.4 so that, instead of calling getClass.getClassLoader() with each invocation, it creates

        private static ClassLoader classLoader = SecurityUtility.getClassLoader(ServerThread.class);

        Should I write a 1000 times "DO NOT CREATE STATIC REFERENCES TO CLASSLOADERS"?

        If you make it an instance variable, does the problem go away? I'd try it but I screwed up my copy of AS 5.0.0.CR2 and I'm still downloading a clean copy from SVN.

        • 16. Re: EJB3 Classloader Leak (EJBTHREE-1442)
          alrubinger

          Brian's correct; my switching over to the TCCL in BaseSessionProxyFactory.createProxyBusiness() leads to a CL Leak. But I'm not convinced that this is the evil piece.

          I *need* this code, and web injection fails without it (see http://www.jboss.com/index.html?module=bb&op=viewtopic&t=141165 for an explanation of why).

          However, this TCCL usage seems awfully hacky to be in EJB3 Proxy; I'd expect to always use the Container CL to generate proxies. This unfortunately will collide when a web CL needs injection and has previously defined the business interfaces with its own CL (which by Servlet Spec must look to itself *first*, and parent delegation second).

          Also interesting is Ron's last post, which I'll look at tomorrow.

          S,
          ALR

          • 17. Re: EJB3 Classloader Leak (EJBTHREE-1442)
            kabirkhan

             

            "ron.sigal@jboss.com" wrote:

            If you make it an instance variable, does the problem go away? I'd try it but I screwed up my copy of AS 5.0.0.CR2 and I'm still downloading a clean copy from SVN.


            You should probably store it in a WeakReference

            • 18. Re: EJB3 Classloader Leak (EJBTHREE-1442)
              brian.stansberry

               

              "ALRubinger" wrote:
              So:

              ejb3-connectors-jboss-beans.xml CL > Proxy Class > Business Interface Class > Deployment CL

              ?

              ...and that's how one CL creates a chain of linked references to the EJB_SLSB CL?


              Yep, that's it.

              I'd tried (unsuccessfully) to limit the alternate proxy creation before, which resulted in errors in web injection.


              Can you elaborate on how it failed? The idea I had on http://www.jboss.com/index.html?module=bb&op=viewtopic&t=141165 of not creating the alternate proxy if the business interface class loaded by the TCCL is the same as the one loaded by the deployment classloader shouldn't have any impact if a version of the business interface class is available via the webapp's WEB-INF and the webapp is using a child-first classloader. The classes wouldn't match and the code would drop into the code that creates the alternate proxy.

              But probably using the TCCL ain't great either; I'll give it another spin.


              One thing that might help is to not use the TCCL to create the proxy; instead use the business interface class' classloader. Whereby this:

              Set<Class<?>> businessInterfaces = new HashSet<Class<?>>();
              businessInterfaces.add(businessInterfaceClass);
              constructor = this.createProxyConstructor(businessInterfaces, tcl);


              the last line becomes:

              constructor = this.createProxyConstructor(businessInterfaces, businessInterfaceClass.getClassLoader());


              This way the ref chain above is broken:

              ejb3-connectors-jboss-beans.xml CL > Proxy Class > Business Interface Class > Deployment CL

              becomes, in the case where the Deployment CL classes are visible to the TCCL:

              Deployment CL > Proxy Class > Business Interface Class > Deployment CL

              and in cases where a different version of the businessInterfaceClass is loaded from the TCCL:

              Webapp CL > Proxy Class > Business Interface Class > Webapp CL

              Neither of those two chains leak the Deployment CL -- at least not to anyplace where it isn't already leaked ;)

              • 19. Re: EJB3 Classloader Leak (EJBTHREE-1442)
                wolfc

                The proxy ends up in the ejb3-connectors class loader, which is wrong. This happens for every remote invocation.

                This shows why:

                Heap walker - Allocations
                Session: JBoss 5.x on localhost
                Time of export: Thursday, September 11, 2008 4:14:46 PM CEST
                JVM time: 83:33
                
                Current object set: 1 instance of java.lang.Class
                Selection steps: 4 selection steps, 16 bytes shallow size
                
                 0.0% - 0 bytes - 0 alloc. org.jboss.remoting.transport.socket.ServerThread.run
                 0.0% - 0 bytes - 0 alloc. org.jboss.remoting.transport.socket.ServerThread.dorun
                 0.0% - 0 bytes - 0 alloc. org.jboss.remoting.transport.socket.ServerThread.processInvocation
                 0.0% - 0 bytes - 0 alloc. org.jboss.remoting.transport.socket.ServerThread.completeInvocation
                 0.0% - 0 bytes - 0 alloc. org.jboss.remoting.ServerInvoker.invoke
                 0.0% - 0 bytes - 0 alloc. org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke
                 0.0% - 0 bytes - 0 alloc. org.jboss.aop.Dispatcher.invoke
                 0.0% - 0 bytes - 0 alloc. java.lang.reflect.Method.invoke
                 0.0% - 0 bytes - 0 alloc. org.jboss.ejb3.proxy.factory.session.SessionProxyFactoryBase.createProxyBusiness
                 0.0% - 0 bytes - 0 alloc. org.jboss.ejb3.proxy.factory.ProxyFactoryBase.createProxyConstructor
                 100.0% - 16 bytes - 1 alloc. java.lang.Class.getConstructor

                The proxy should have ended up in the same class loader as the business interface. That's the job of the ObjectFactory.

                • 20. Re: EJB3 Classloader Leak (EJBTHREE-1442)
                  ron_sigal

                  Second thoughts about the static classloader reference in ServerThread. It's a static field so it's stored in ServerThread.class, right? So it's just a class pointing to its classloader. That doesn't sound like a problem, does it?

                  • 21. Re: EJB3 Classloader Leak (EJBTHREE-1442)
                    alrubinger

                     

                    "ron.sigal@jboss.com" wrote:
                    That doesn't sound like a problem, does it?


                    I haven't found evidence it's a problem yet, Ron. :)

                    I'm using the wrong CL to create Proxies, so working that angle now.

                    S,
                    ALR

                    • 22. Re: EJB3 Classloader Leak (EJBTHREE-1442)
                      anil.saldhana

                       

                      "ron.sigal@jboss.com" wrote:
                      Second thoughts about the static classloader reference in ServerThread. It's a static field so it's stored in ServerThread.class, right? So it's just a class pointing to its classloader. That doesn't sound like a problem, does it?


                      Does that static field ever get cleared?

                      • 23. Re: EJB3 Classloader Leak (EJBTHREE-1442)
                        alrubinger

                        I've got a patch that fixes the test in Sun JDK6, and JDK5 i386. Still continues to fail, however, in JDK5 x86_64.

                        This solution will also address the web injection issue by redefining the Proxy in the caller's CL if necessary.

                        S,
                        ALR

                        Index: src/main/java/org/jboss/ejb3/proxy/factory/session/SessionProxyFactoryBase.java
                        ===================================================================
                        --- src/main/java/org/jboss/ejb3/proxy/factory/session/SessionProxyFactoryBase.java (revision 78381)
                        +++ src/main/java/org/jboss/ejb3/proxy/factory/session/SessionProxyFactoryBase.java (working copy)
                        @@ -197,30 +197,6 @@
                         Constructor<?> constructor = this.getConstructorsProxySpecificBusinessInterface().get(
                         businessInterfaceName.trim());
                        
                        - /*
                        - * In place for web injection (isolated CL)
                        - */
                        - ClassLoader tcl = Thread.currentThread().getContextClassLoader();
                        - try
                        - {
                        - // See if we can get at the bean class from the TCL
                        - Class<?> businessInterfaceClass = Class.forName(businessInterfaceName, false, tcl);
                        -
                        - // If so, use the TCL to generate the Proxy class, not the Container CL
                        - Set<Class<?>> businessInterfaces = new HashSet<Class<?>>();
                        - businessInterfaces.add(businessInterfaceClass);
                        - constructor = this.createProxyConstructor(businessInterfaces, tcl);
                        -
                        - }
                        - catch (LinkageError le)
                        - {
                        - // Ignore
                        - }
                        - catch (ClassNotFoundException cce)
                        - {
                        - // Ignore
                        - }
                        -
                         // Ensure the constructor was found
                         assert constructor != null : "No business proxy constructor for \"" + businessInterfaceName
                         + "\" was found; not created at start() properly? Bad value bound as RefAddr in JNDI?";
                        @@ -229,8 +205,11 @@
                         SessionProxyInvocationHandler handler = this
                         .createBusinessInterfaceSpecificInvocationHandler(businessInterfaceName);
                        
                        - // Create a new Proxy instance, and return
                        - return constructor.newInstance(handler);
                        + // Create a new Proxy instance
                        + Object proxy = constructor.newInstance(handler);
                        +
                        + // Return
                        + return proxy;
                         }
                         catch (Throwable t)
                         {
                        Index: src/main/java/org/jboss/ejb3/proxy/objectfactory/session/SessionProxyObjectFactory.java
                        ===================================================================
                        --- src/main/java/org/jboss/ejb3/proxy/objectfactory/session/SessionProxyObjectFactory.java (revision 78381)
                        +++ src/main/java/org/jboss/ejb3/proxy/objectfactory/session/SessionProxyObjectFactory.java (working copy)
                        @@ -21,8 +21,12 @@
                         */
                         package org.jboss.ejb3.proxy.objectfactory.session;
                        
                        +import java.lang.reflect.InvocationHandler;
                        +import java.lang.reflect.Proxy;
                        +import java.util.HashSet;
                         import java.util.List;
                         import java.util.Map;
                        +import java.util.Set;
                        
                         import javax.naming.Name;
                        
                        @@ -129,6 +133,65 @@
                         proxy = sFactory.createProxyBusiness(businessInterface);
                         log.debug("Created Proxy of type " + proxy.getClass().getSimpleName() + " for EJB3 Business Interface: "
                         + businessInterface);
                        +
                        + /*
                        + * We've got to ensure that the Proxy will be assignable to the target
                        + * within this CL
                        + */
                        +
                        + // Get the TCL
                        + ClassLoader tcl = Thread.currentThread().getContextClassLoader();
                        +
                        + // Get the Proxy's CL
                        + ClassLoader proxyCl = proxy.getClass().getClassLoader();
                        +
                        + // If the classloaders are not equal
                        + if (tcl != proxyCl)
                        + {
                        + /*
                        + * Reconstruct/redefine the Proxy in our CL
                        + */
                        +
                        + // Get the Proxy Class
                        + Class<?> proxyClass = proxy.getClass();
                        +
                        + // Ensure we've got a Proxy
                        + assert Proxy.isProxyClass(proxyClass) : "Assumed Proxy is not an instance of " + Proxy.class.getName();
                        +
                        + // Get the InvocationHandler
                        + InvocationHandler handler = Proxy.getInvocationHandler(proxy);
                        +
                        + // Get the Interfaces
                        + Class<?>[] proxyInterfaces = proxyClass.getInterfaces();
                        +
                        + // Make a Set to hold the redefined classes
                        + Set<Class<?>> ourClInterfaces = new HashSet<Class<?>>();
                        +
                        + // For each interface defined by the Proxy
                        + for (Class<?> proxyInterface : proxyInterfaces)
                        + {
                        + // Get the FQN
                        + String proxyInterfaceName = proxyInterface.getName();
                        +
                        + // Redefine the class in our CL
                        + Class<?> ourDefinedProxyInterface = null;
                        + try
                        + {
                        + ourDefinedProxyInterface = Class.forName(proxyInterfaceName, false, tcl);
                        + }
                        + catch (ClassNotFoundException e)
                        + {
                        + throw new RuntimeException("Can not find interface declared by Proxy in our CL + " + tcl, e);
                        + }
                        +
                        + // Add the Class to the Set
                        + ourClInterfaces.add(ourDefinedProxyInterface);
                        + }
                        +
                        + // Redefine the Proxy in our CL
                        + proxy = Proxy.newProxyInstance(tcl, ourClInterfaces.toArray(new Class<?>[]
                        + {}), handler);
                        + }
                         }
                         else
                         {


                        • 24. Re: EJB3 Classloader Leak (EJBTHREE-1442)

                          Is there a work around on this issue? I am running Windows Vista 64bit, Sun JDK6 x64 and JBoss 5.1 and am experiencing EJB Timer issue associated with this classloading.

                          Any help is greatly appreciated. Thanks.

                          ===============
                          Caused by: java.lang.RuntimeException: Can not find interface declared by Proxy in our CL + BaseClassLoader@1bf1a64c{vfsfile:/C:/JudoFS/server/onex/server/etx/deploy/ejb2-timer-service.xml}
                          at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.redefineProxyInTcl(ProxyObjectFactory.java:343)
                          at org.jboss.ejb3.proxy.impl.objectfactory.session.SessionProxyObjectFactory.createProxy(SessionProxyObjectFactory.java:134)
                          at org.jboss.ejb3.proxy.impl.objectfactory.session.stateless.StatelessSessionProxyObjectFactory.getProxy(StatelessSessionProxyObjectFactory.java:79)
                          at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getObjectInstance(ProxyObjectFactory.java:158)
                          at javax.naming.spi.NamingManager.getObjectInstance(Unknown Source)
                          at org.jnp.interfaces.NamingContext.getObjectInstance(NamingContext.java:1479)
                          at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1496)
                          ... 45 more
                          Caused by: java.lang.ClassNotFoundException: com.judofs.exchange.scheduler.taskexecutor.TaskExecutorDirectoryLocal from BaseClassLoader@1bf1a64c{VFSClassLoaderPolicy@15dcd5e9{name=vfsfile:/C:/JudoFS/server/onex/server/etx/deploy/ejb2-timer-service.xml domain=ClassLoaderDomain@54e0d16b{name=DefaultDomain parentPolicy=BEFORE parent=org.jboss.bootstrap.NoAnnotationURLClassLoader@2cb0ce8f} roots=[MemoryContextHandler@1432338229[path= context=vfsmemory://4p722x4o-81jb3e-g1ln4cot-1-g1ln5dj0-12 real=vfsmemory://4p722x4o-81jb3e-g1ln4cot-1-g1ln5dj0-12]] delegates=null exported=[] <IMPORT-ALL>NON_EMPTY}}
                          at org.jboss.classloader.spi.base.BaseClassLoader.loadClass(BaseClassLoader.java:448)
                          at java.lang.ClassLoader.loadClass(Unknown Source)
                          at java.lang.ClassLoader.loadClassInternal(Unknown Source)
                          at java.lang.Class.forName0(Native Method)
                          at java.lang.Class.forName(Unknown Source)
                          at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.redefineProxyInTcl(ProxyObjectFactory.java:339)
                          ... 51 more

                          • 25. Re: EJB3 Classloader Leak (EJBTHREE-1442)
                            jaikiran

                            Please create a separate thread in the EJB3 user forum here http://www.jboss.org/index.html?module=bb&op=viewforum&f=221.

                            As for your specific issue, the latest version of our plugin http://www.jboss.org/ejb3/ejb3plugin.html contains the fix.

                            You can download the plugin here http://www.jboss.org/ejb3/downloads.html

                            For any further related questions, please create a thread in the user forum.

                            1 2 Previous Next