C# MSMQ BeginPeek/PeekCompleted memory leak - Need some help

Posted on 2005-04-13
Last Modified: 2010-06-22
I've got an server app in C# that is basically sitting there waiting for messages to arrive in MSMQ from somewhere else.  I use a BeginPeek( timeout, IASyncResult) call to start the whole process. When the peekCompleted event fires, I disconnect the event handler and then I check to see why it fired. If it's because of a message I deal with the messages. If it is because the timeout expired, I reattach the event handler and call BeginPeek() again.

The problem is that my application is sitting idle, with no messages in the queue and each iteration of BeginPeek/PeekCompleted is leaking object handles. I discovered this by looking at the Task Manager at first. Then by using the .Net Memory Profiler by Sci-Tech. I was able to track down where it was occuring.

Each iteration is leaking 1 Message object and one ManualResetEvent object.

But there can't be any message object because there aren't any messages in the queue! I'm not storing a reference to what EndPeek() returns because I don't care what it is if it's a message my message handling code will take care of it. If its not a message all I need to do is move on and start the 'loop' over again.

Anyone have any idea what's going on or better yet how to fix it? I'm leaking 2 handles every 3 seconds or so and obviously that's a problem. I can post code if need be. It's not really all that complicated what I'm doing which is why it's so confusing and aggravating that it's leaking memory.
Question by:lrwdigital
    LVL 23

    Accepted Solution

    The .NET garbage collector doesn't do anything until memory gets tight.  You might try doing your own periodic GC.Collect() to see if that improves matters.

    Author Comment

    Unfortunately, even if I do a GC, which I'm pretty loathe to do, it doesn't guarantee that anything will happen since the CRL is what determines when garbage is actually collected.

    I can see by the .Net Memory Profiler that stuff IS being collected... and these instances are not. Therefore calling to the GC isn't going to do anything anyway. Additionally calling the GC will slow down the app and create more overhead.

    What I need is a way to keep the leak from happening in the first place.

    Author Comment

    Don't know if this means anything but from looking in the debugger window...

    the PeekCompletedEventArgs contains an something called -      [System.Messaging.MessageQueue.AsynchronousRequest]

    This class, has as one of the properties of it, a message object. The message object's properties seem to be largely exceptions of SystemInvalidOperationException type though not all of them. Two of them that stand out to me are the onCompletionStatusChanged property ( which contains a System.Threading.IOCompletionCallback) and the resetEvent property ( which contains an ManualResetEvent ). There is also a reference to a Message directly attached to the PeekCompletedEventArgs class through the Message property but it just shows up as an exception of MessageQueueException type.

    Oddly enough the IAsyncResult that I get back from the BeginPeek( ) has the same things in it except for no public accessor to the message object that's screwed up. My count of undisposed Message object always goes up on the line of .BeginPeek(). But I don't really know how to force this object to dispose of itself and not hang around. I tried to cast the IAsyncResult as the AsynchronousRequest but the compiler doesn't think it exists ( a non-public class perhaps? ).

    the .Net Memory profiler says that these objects root back to System.Threading's IOCompletionCallback. and the the last thing callstack says MessageQueue.ReceiveAsync( ).


    Anyone have an idea how to get rid of these extra instances?

    Author Comment

    I figured I would test to make sure that it's not some sort of weird remoting voodoo ( since I am remoting in the above app ) and thus wrote a quick test app. All the test app does is attach to a queue ( or create a queue if it doesn't exit ), once set up it calls .BeginPeek() as above. There is additional functionality added to allow me to toss a message into the queue and retreive it but that's all she wrote. Nothing fancy there...

    It's basically just...

    queue.PeekCompleted+= new PeekCompletedEventHandler( queue_PeekCompleted);
    queue.BeginPeek( timeout );

    private void queue_PeekCompleted(object sender, PeekCompletedEventArgs e)
                Console.Write("Taking a peek...");
                queue.EndPeek( e.AsyncResult );
          catch( MessageQueueException ex )
                if ( ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout )
                      Console.WriteLine("Peek timeout");
                if ( ! this.queueShutdown )
                      queue.BeginPeek( PEEK_TIMEOUT, e.AsyncResult.AsyncState );
                      KillQueue( );

    In the last hour the BeginPeek() has leaked 2,664 message objects and 2,673 ManualResetEvents.

    Expert Comment

    Hi lrwdigital,

    Did you get a better answer to this? I'm trying to work out if not calling EndPeek is a problem. In your test app in your last post you're not calling EndPeek if there is a timeout. I'm wanting to do something similar - just use BeginPeek as an initiator of an async event, raised in my PeekCompleted event handler. Then something listenting on that event can call-back into my peeking class to get it to call Receive(messageId), then on return from the event raised by my peeking class, at the end of the PeekCompleted function, I do a BeginPeek again. i.e. there's no EndPeek call.

    It seems to me that whatever the initial IAsyncReset represents (and whatever it is referencing) may still be haning around... unless the fact that the completion of the execution of the PeekCompleted implements the releasing of the thread (to the thread pool) and dereferences the IAsyncResult stuff. But I'm not certain what happens. Any instights?

    Hmmm. Just seen that this is a 2005 question. Hopefully you're still out there and remember what this is all about.

    LVL 75

    Expert Comment

    by:Michel Plungjan

    Featured Post

    What Should I Do With This Threat Intelligence?

    Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

    Join & Write a Comment

    Suggested Solutions

    Title # Comments Views Activity
    FizzBuzz challenge 9 65
    Modbus - whats the maximum I can store in one register? 4 70
    strCount chalenge 3 36
    mapAB Challlenge 35 55
    Entering a date in Microsoft Access can be tricky. A typo can cause month and day to be shuffled, entering the day only causes an error, as does entering, say, day 31 in June. This article shows how an inputmask supported by code can help the user a…
    Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
    In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …
    In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

    754 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    24 Experts available now in Live!

    Get 1:1 Help Now