Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: 3.1.2_b23, 3.1.2
    • Fix Version/s: 4.0_b75
    • Component/s: web_services
    • Labels:
      None

      Description

      Usage of @WebService causes to memory leak on every endppoint call.

      Cause of problem:
      org.glassfish.webservices.InstanceResolverImpl<T>

      On the call to
      @Override
      public Object invoke(Packet p, Method m, Object... args) throws InvocationTargetException, IllegalAccessException

      { return m.invoke( resolve(p), args ); }

      it calls "resolve" method, which calls injManager.createManagedObject(classtobeResolved); and creates new managed object and stores in the class field.

      Also, one of our Spring-based application works normal way, for some reason com.sun.xml.ws.server.SingletonResolver is used instead of InstanceResolverImpl.

      There is the dispose method, which can destroy it appropriate way. But it will be called only in case of call to SEIInvokerTube.preDestroy. As I know it is only called while endpoint unregestering.

      So, on every new call to endpoint, InstanceResolverImpl create new managed object without attempt to destroy previous. After a week of our JVM contains about 200000 of such objects.

      So, to fix it more fast way "resolve" of InstanceResolverImpl method may to be changed to:

      public @NotNull T resolve(Packet request) {
      //See iss 9721
      //Injection and instantiation is now done lazily

      try {
      // NEW STARTS HERE
      if (instance != null)

      { injManager.destroyManagedObject(instance); instance = null; // to be sure will not be reused in case of exception inside createManagedObject }

      // NEW ENDS HERE
      instance = injManager.createManagedObject(classtobeResolved);
      } catch (InjectionException e)

      { throw new WebServiceException(e); }

      resolver = InstanceResolver.createSingleton(instance);
      getResourceInjector(endpoint).inject(wsc, instance);
      return resolver.resolve(request);
      }

        Activity

        Hide
        michail.nikolaev added a comment -

        There is a possible temporal workaround:

        1) add to dependency

        <dependency>
        <groupId>org.glassfish.main.common</groupId>
        <artifactId>container-common</artifactId>
        <version>3.1.2</version>
        <scope>provided</scope>
        </dependency>

        <dependency>
        <groupId>org.glassfish.main.webservices</groupId>
        <artifactId>jsr109-impl</artifactId>
        <version>3.1.2</version>
        <scope>provided</scope>
        </dependency>

        2) Create class like
        public class WebSingletonResolver<T> extends InstanceResolver<T> {
        private final Class<T> clazzToBeResolved;
        private final InjectionManager injManager =
        WebServiceContractImpl.getInstance().getHabitat().getByContract(InjectionManager.class);
        private final ThreadLocal<T> instance = new ThreadLocal<T>();
        private WSEndpoint endpoint;
        private WSWebServiceContext wsc;

        public WebSingletonResolver(@NotNull Class<T> clazz)

        { this.clazzToBeResolved = clazz; }

        public @NotNull
        T resolve(Packet request) {
        if (instance.get() != null)

        { return instance.get(); }

        init();

        return instance.get();
        }

        private void init() {
        try

        { instance.set(injManager.createManagedObject(clazzToBeResolved)); }

        catch (InjectionException e)

        { throw new WebServiceException(e); }

        getResourceInjector(endpoint).inject(wsc, instance.get());
        }

        public void start(WSWebServiceContext wsc, WSEndpoint endpoint) { this.wsc = wsc; this.endpoint = endpoint; }

        public void dispose() {
        try {
        if (instance.get() != null) { // instance can be null as it is created laziily injManager.destroyManagedObject(instance.get()); instance.set(null); }
        } catch (InjectionException e) { throw new WebServiceException(e); }

        }

        private ResourceInjector getResourceInjector(WSEndpoint endpoint) {
        ResourceInjector ri = endpoint.getContainer().getSPI(ResourceInjector.class);
        if (ri == null)

        { ri = ResourceInjector.STANDALONE; }

        return ri;
        }
        }
        3) create annotation like
        @InstanceResolverAnnotation(WebSingletonResolver.class) @Target(TYPE) @Retention(RUNTIME)
        public @interface WebSingleton {
        }
        4) annotate endpoint like
        @WebService(serviceName = "XXXXService",
        endpointInterface = "com.xxx.XXXXService",
        targetNamespace = "http://xxx.com/")
        @WebSingleton

        Show
        michail.nikolaev added a comment - There is a possible temporal workaround: 1) add to dependency <dependency> <groupId>org.glassfish.main.common</groupId> <artifactId>container-common</artifactId> <version>3.1.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.glassfish.main.webservices</groupId> <artifactId>jsr109-impl</artifactId> <version>3.1.2</version> <scope>provided</scope> </dependency> 2) Create class like public class WebSingletonResolver<T> extends InstanceResolver<T> { private final Class<T> clazzToBeResolved; private final InjectionManager injManager = WebServiceContractImpl.getInstance().getHabitat().getByContract(InjectionManager.class); private final ThreadLocal<T> instance = new ThreadLocal<T>(); private WSEndpoint endpoint; private WSWebServiceContext wsc; public WebSingletonResolver(@NotNull Class<T> clazz) { this.clazzToBeResolved = clazz; } public @NotNull T resolve(Packet request) { if (instance.get() != null) { return instance.get(); } init(); return instance.get(); } private void init() { try { instance.set(injManager.createManagedObject(clazzToBeResolved)); } catch (InjectionException e) { throw new WebServiceException(e); } getResourceInjector(endpoint).inject(wsc, instance.get()); } public void start(WSWebServiceContext wsc, WSEndpoint endpoint) { this.wsc = wsc; this.endpoint = endpoint; } public void dispose() { try { if (instance.get() != null) { // instance can be null as it is created laziily injManager.destroyManagedObject(instance.get()); instance.set(null); } } catch (InjectionException e) { throw new WebServiceException(e); } } private ResourceInjector getResourceInjector(WSEndpoint endpoint) { ResourceInjector ri = endpoint.getContainer().getSPI(ResourceInjector.class); if (ri == null) { ri = ResourceInjector.STANDALONE; } return ri; } } 3) create annotation like @InstanceResolverAnnotation(WebSingletonResolver.class) @Target(TYPE) @Retention(RUNTIME) public @interface WebSingleton { } 4) annotate endpoint like @WebService(serviceName = "XXXXService", endpointInterface = "com.xxx.XXXXService", targetNamespace = "http://xxx.com/") @WebSingleton
        Hide
        shreedhar_ganapathy added a comment -

        Possible WS impl bug. Reassign if not appropriate

        Show
        shreedhar_ganapathy added a comment - Possible WS impl bug. Reassign if not appropriate
        Hide
        Martin Grebac added a comment -

        Lukasi, would you please evaluate this? Thanks.

        Show
        Martin Grebac added a comment - Lukasi, would you please evaluate this? Thanks.
        Show
        Lukas Jungmann added a comment - http://java.net/projects/glassfish/sources/svn/revision/59316

          People

          • Assignee:
            Lukas Jungmann
            Reporter:
            michail.nikolaev
          • Votes:
            2 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: