Vb.Net WebBrowser object memory leak - HELP!

kepler

New member
I made a load test harness for a site and at given intervals it fires this method. For some reason, the two WebBrowser.Navigate methods in the centre cause a huge memory leak. I'm setting them to nothing and calling the garbage collector in the Finally block but it makes no difference.

With the two Navigate lines commented out, no memory leak.

Are there issues with the WebBrowser object? Do they require flushing somehow before garbage collection, or have I just completely missed something? :confused:
Code:
    Private Sub TimerWB_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimerWB.Tick
        Dim strManufacturerCollectionPage As String
        Dim strProductCollectionPage As String
        Dim nPos1 As Integer, nPos2 As Integer
        wbManCollection = New WebBrowser
        wbProductCollection = New WebBrowser
        Try

            nPos1 = mWebCount Mod mAL_WebTest1.Count
            nPos2 = mWebCount Mod mAL_WebTest2.Count
            strManufacturerCollectionPage = mAL_WebTest1.Item(nPos1)
            strProductCollectionPage = mAL_WebTest2.Item(nPos2)

            ' *** This is the manufacturers web request
            wbManCollection.Navigate(strManufacturerCollectionPage)
            ' *** This is the product collection web request
            wbProductCollection.Navigate(strProductCollectionPage)

            ShowWebFeedback("Iteration number: " & mWebCount)
            mWebCount = mWebCount + 1

            ' Update the Req/Sec rating
            UpdateWPReqSec()

        Catch ex As Exception
            cLog.logException(ex)
        Finally
            strManufacturerCollectionPage = Nothing
            strProductCollectionPage = Nothing
            nPos1 = Nothing
            nPos2 = Nothing
            wbManCollection = Nothing
            wbProductCollection = Nothing
            GC.WaitForPendingFinalizers()
            GC.Collect()
        End Try
    End Sub
 
I made a load test harness for a site and at given intervals it fires this method. For some reason, the two WebBrowser.Navigate methods in the centre cause a huge memory leak. I'm setting them to nothing and calling the garbage collector in the Finally block but it makes no difference.

With the two Navigate lines commented out, no memory leak.

Are there issues with the WebBrowser object? Do they require flushing somehow before garbage collection, or have I just completely missed something? :confused:
Code:
    Private Sub TimerWB_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimerWB.Tick
        Dim strManufacturerCollectionPage As String
        Dim strProductCollectionPage As String
        Dim nPos1 As Integer, nPos2 As Integer
        wbManCollection = New WebBrowser
        wbProductCollection = New WebBrowser
        Try

            nPos1 = mWebCount Mod mAL_WebTest1.Count
            nPos2 = mWebCount Mod mAL_WebTest2.Count
            strManufacturerCollectionPage = mAL_WebTest1.Item(nPos1)
            strProductCollectionPage = mAL_WebTest2.Item(nPos2)

            ' *** This is the manufacturers web request
            wbManCollection.Navigate(strManufacturerCollectionPage)
            ' *** This is the product collection web request
            wbProductCollection.Navigate(strProductCollectionPage)

            ShowWebFeedback("Iteration number: " & mWebCount)
            mWebCount = mWebCount + 1

            ' Update the Req/Sec rating
            UpdateWPReqSec()

        Catch ex As Exception
            cLog.logException(ex)
        Finally
            strManufacturerCollectionPage = Nothing
            strProductCollectionPage = Nothing
            nPos1 = Nothing
            nPos2 = Nothing
            wbManCollection = Nothing
            wbProductCollection = Nothing
            GC.WaitForPendingFinalizers()
            GC.Collect()
        End Try
    End Sub

The webbrowser control still has the underlying COM control that performs most of the work. You create 2 instances of it in this method and call Navigate. Navigate is a an asynchronous function that returns a NavigateComplete event when the page is fully loaded. You must be creating a problem by allocating the WebBrowsers and then trying to collect them while a Navigate is still in progress. I would suggest creating your Web Browsers during construction and not everytime your timer goes off.

Also, I would recommend never calling GC.Collect inside your code. This is a huge performance issue. The .NET GC is optimized. Forcing your own collections is just causing a LOT of expensive memory management calls before they are needed.
 
Thanks for the reply.
The webbrowser control still has the underlying COM control that performs most of the work. You create 2 instances of it in this method and call Navigate. Navigate is a an asynchronous function that returns a NavigateComplete event when the page is fully loaded. You must be creating a problem by allocating the WebBrowsers and then trying to collect them while a Navigate is still in progress. I would suggest creating your Web Browsers during construction and not everytime your timer goes off.
You're right about the code being smelly and counter-productive, but I tried the way you've described it originally I'm afraid and no joy, still a consistent linear memory leak. I should mention, if the tick is set to be slow, say, 20 seconds (considering the pages requested will be about 2-20k, and hosted locally), the leak is still evident.
Also, I would recommend never calling GC.Collect inside your code. This is a huge performance issue. The .NET GC is optimized. Forcing your own collections is just causing a LOT of expensive memory management calls before they are needed.
Completely right, that was just a noobish desperation shot in the dark really.
 
You can't really measure a straight memory leak in .NET by watching memory grow. The GC frees memory when it needs it. So, just because you are done with your web page doesn't mean that .NET will deallocate the space used. Your memory will always grow linearly and then all of a sudden, the GC will kick in and free a bunch. The whole idea of having a memory manager is to efficiently manage memory for you. This means that memory will not be de-allocated when you expect it should. Instead .NET will wait until an opportune time to re-allocate memory in large bunches.

Unmanaged resources are the real problems that could cause memory leaks. I don't think there are issues related to unmanaged resources using the WebBrowser control, but there may be. Take a look at some information relate to the IDispose interface. Some objects need you to call a Close method to be sure that all unmanaged resources are free. It is not enough to just set the reference to the object to Nothing You need to also be sure and make the appropiate call to free all unmanaged resources. (For example file handles, window handles, ...)
 
You can't really measure a straight memory leak in .NET by watching memory grow. The GC frees memory when it needs it. So, just because you are done with your web page doesn't mean that .NET will deallocate the space used. Your memory will always grow linearly and then all of a sudden, the GC will kick in and free a bunch. The whole idea of having a memory manager is to efficiently manage memory for you. This means that memory will not be de-allocated when you expect it should. Instead .NET will wait until an opportune time to re-allocate memory in large bunches.
Unfortunately this one didn't clear up and finally caused javascript Out Of Memory errors that stopped that area of the test. In the end I've switched to using simple HttpRequests. It amounts to pretty much the same thing for the purposes of the test and doesn't seem to have the same memory issues.
 
Back
Top