WebResponse.Close() not disposing unmanaged resource?

C

cmbardon

I have a .net app that uses a lot of calls to System.Net.WebRequest,
and it appears to be leaking memory. I've spent a couple of days
working with the excellent .net memory profiler from Scitech
(http://www.scitech.se/) trying to find the leak, and all I've managed
to find is that the win32 (unmanaged) heap seems to keep growing. I
wrote this (pretty non-realistic) code in a test app to try duplicating
the problem:

while(true)
{
try
{
System.Net.WebRequest
req=System.Net.WebRequest.Create(@"http://chris/TestWebService/TestService.asmx?WSDL");
System.Net.WebResponse resp=req.GetResponse();
resp.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}


Note that this was just inside a button click event of a winform
application. The exception condition never got hit, and the app just
kept hammering away at my local web server. Checking the profiler, I
saw the number of undisposed instances of System.Net.HttpWebResponse,
System.Net.ConnectStream, and System.Threading.ManualResetEvent
increasing with each iteration. Shouldn't the resp.Close() statement
release the resources? There's nothing in the documentation about
doing any sort of disposal on the request object, so it appears that
only the response needs to be disposed, and so far, that doesn't seem
to be happening. I've also tried the above code casting the response to
an HTTPWebResponse, but that has no effect. I also tried removing the
resp.Close() statement, which had no effect (the undisposed objects
still showed up in the profiler). Is there something else I need to do
to fix this memory leak?

Thanks for your help,

Chris
 
M

Michael Höhne

Hi Chris,

don't know if makes any change, but the WebResponse class implements the
IDisposable interface, so you could try a using statement:

using (System.Net.WebResponse resp=req.GetResponse()) {
// do some stuff with resp if you want.
}

If there's any cleanup code in the WebRespone.Dispose implementation, it
will be executed as soon as the using block is left and it will be executed
even if an exception is thrown.

Michael
 
C

cmbardon

Thanks for the reply Michael. I tried your suggestion just after I
posted actually, and I found that putting the using statement in got
rid of the undisposed webResponse objects, but left the
System.Net.ConnectStream and System.Threading.ManualResetEvent objects
undisposed. I know that the ManualResetEvent is created by
HTTPWebRequest.GetResponse, and the ConnectStream is called by
HttpWebRequest.BeginSubmitRequest.

The first problem is that these last two undisposed instances are
created by the request, which does not implement IDisposable, and does
not have anything in the documentation regarding unmanaged resources.
Is there something that I need to do to clean up after a WebRequest?

Second, why does the using statement work for the response, but not the
close() method? The documentation explicitly states :

"The Close method closes the response stream and releases the
connection to the Internet resource for reuse by other requests. Note
You must call either the Stream.Close or the HttpWebResponse.Close
method to close the stream and release the connection for reuse. It is
not necessary to call both Stream.Close and HttpWebResponse.Close, but
doing so does not cause an error. Failure to close the stream will
cause your application to run out of connections."

Does this mean that Close() doesn't actually call Dispose()? I'm a
little confused-I thought that this was the reason that the close
method existed on stream objects. The code that I'm using is almost
identical to the MSDN sample code.
 
G

Guest

I had this exact same issue. I worked with MS and they gave me a hotfix that
fixed the problem. There is a KB article that you can use to get the hotfix,
however, the KB doesn't describe the problem. The rep I worked with said this
hotfix fixes a few other undocumented issues. This is one of them.

http://support.microsoft.com/?kbid=907432

I ran a load on the server overnight and it worked great.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top