4 Replies Latest reply on May 13, 2008 9:01 PM by ron_sigal

    Memory leak in remoting objects

    harish43

      I had originally posted this on the JBoss Messaging forum and was asked to post here.

      The original post is at:
      http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4148677#4148677

      As mentioned in the original post, I have run tests with the Example Queue app that comes with the JBoss Messaging distribution that seem to indicate memory leak with the following JBoss Remoting objects.

      org.jboss.remoting.transport.bisocket.BisocketClientInvoker$PingTimerTask
      org.jboss.remoting.transport.bisocket.BisocketClientInvoker$BooleanHolder

      Other tests show the following objects growing
      org.jboss.remoting.transport.bisocket.BisocketServerInvoker
      org.jboss.remoting.loading.ClassByteClassLoader
      org.jboss.remoting.transport.bisocket.BisocketServerInvoker$ControlMonitorTimerTask


      I appreciate any help regarding this.

        • 1. Re: Memory leak in remoting objects
          ron_sigal

          Every time you create a JBossMessaging connection, you're creating a Remoting bisocket connection, including a new BisocketClientInvoker.$PingTimerTask. When you close the JBM connection, the PingTimerTask should cancel itself.

          You're sure that you're closing the JBM connection?

          Now, the Timer that the PingTimerTasks are registered with is a static object, so I guess it's possible that the Timer is holding references to old PingTimerTasks. I don't know how you're profiling your test, but I know that with JProfiler you can see what's pointing to the PingTimerTasks and preventing them from getting garbage collected.

          Could you look into that?

          Thanks,
          Ron

          • 2. Re: Memory leak in remoting objects
            trustin

            It's a kind of bug in java.util.Timer. Calling TimerTask.cancel() causes the registered task from being dereferenced in Timer's internal data structure. It is because the Timer developers assumed that the cancellation of tasks would not happen that often.

            The solution is probably destroying the parent Timer class and create a new one. In Java 5, java.util.concurrent.ScheduledThreadPoolExecutor provides a method that purges the references to the cancelled tasks. It's so inconvenient anyway.

            • 3. Re: Memory leak in remoting objects
              trustin

               

              "trustin" wrote:
              Calling TimerTask.cancel() causes the registered task from being dereferenced in Timer's internal data structure.


              This sentence should be:

              Calling TimerTask.cancel() prevents the registered task from being dereferenced in Timer's internal data structure.

              • 4. Re: Memory leak in remoting objects
                ron_sigal

                Hey Trustin,

                I'm seeing something different. When I run

                 for (int i = 0; i < 1000; i++)
                 {
                 Client client = new Client(clientLocator, clientConfig);
                 client.connect();
                 TestCallbackHandler callbackHandler = new TestCallbackHandler();
                 client.addListener(callbackHandler, null, null, true);
                // client.removeListener(callbackHandler);
                 client.disconnect();
                 }
                


                I get lots of BisocketClientInvokers and BisocketClientInvoker.PingTimerTasks hanging around. When I uncomment the client.removeListener() line, I see something different. In particular, I still see lots of BisocketClientInvokers hanging around, but the only reference to them is a java.lang.ref.Finalizer weak reference. For some reason, when I force a garbage collection in JProfiler, the garbage collector doesn't collect them. Maybe the program isn't running long enough to do a full garbage collection? When the program concludes (but stays alive in JProfiler) I can garbage collect all of the BisocketClientInvokers and PingTimerTasks.

                What I just described happens in Windows with jdk 1.5. When I run the same program in linux, the garbage collector is willing to collect the old BisocketClientInvokers, even when the program is still running.

                So it doesn't look like a real leak to me, as long as the program properly disposes of its connections. It looks more like an artifact of the garbage collector behavior.

                -Ron