Roy Osherove

View Original

Problem and Solution: Weird MSMQ memory leak when calling Peek()

I was recently faced with the task of trying to figure out why, sporadically, when Calling an MSMQ's Peek() function, an application would loose memory for no apparent reason. It was pretty weird and hard to even recreate.
Searching google turned up this very helpful news group message which seems to have answered the problem:
 
 
----SNIP------------
If you try to peek or receive messages on a remote queue which does not exist (the queue or the machine) you
will loose memory for every try you do.
The bad part is that there is no direct way to check if a remote queue exists, but there is a workaround.

MessageQueue.Exists(queuename) only works for local queues. If you try to send a message to a queue using this
format name “FormatName:direct=os:<machinename>\private$\myqueue”  you will not get an error if the queue does
not exists. If you try to peek or receive you get an error, but at that point the memory is already lost.



Sample code to reproduce memory leak:

      MessageQueue mq = new MessageQueue("FormatName:direct=OS:dcc-roger-test\\private$\\1234");
      System.Messaging.Message msg = new System.Messaging.Message();                                 

      try                                                                                            
      {                                                                                              
            msg = mq.Peek(TimeSpan.FromTicks(2));                                                 
      }                                                                                              
      catch                                                                                          
      {                                                                                              
      }                                                                                              

      if(msg != null)                                                                                
      {                                                                                              
            msg.Dispose();                                                                           
      }                                                                                              

      mq.Close();                                                                                    
      mq.Dispose();                                                                                  

                                                                                                     
Forcing a GC.Collect / GC.WaitForPendingFinalizers / GC.GetTotalMemory(true) gives back a small portion of the lost memory.
Be aware of the virtual memory usage of your .net applications, in my example I had about 15mb in “mem usage” in Task Manager
and over 1 gb in virtual memory usage.

The workaround is simple, just make sure you can read from the queue before you try to peek / receive from it. CanRead returns
false if the queue does not exist or if you do not have rights to access it.

      if(mq.CanRead)                                                                                 
      {                                                                                              
            msg = mq.Peek(TimeSpan.FromTicks(2));                                                    
      }                                                                                              


Best Regards,
Roger Larsen
Dialogic Communications Corporation
----SNIP------------