Control.Visible = False causing undisposed child instances

Use this forum for questions on how to use .NET Memory Profiler and how to analyse memory usage.
Post Reply
QScend
Posts: 8
Joined: Tue Mar 04, 2008 5:40 pm

Control.Visible = False causing undisposed child instances

Post by QScend » Thu Mar 20, 2008 4:22 pm

Using the following VB .NET code:


Namespace Controls
Public Class Test
Inherits WebControl
Implements INamingContainer

Private ctlGloMiniControl As New MiniControl

Protected Overrides Sub CreateChildControls()
MyBase.CreateChildControls()
Controls.Add(ctlGloMiniControl)
'ctlGloMiniControl.Visible = False 'Uncomment me!
End Sub

End Class
End Namespace

Namespace Controls
Public Class MiniControl
Inherits WebControl
Implements INamingContainer

Private ctlGloTinyControl As New TinyControl

Protected Overrides Sub CreateChildControls()
MyBase.CreateChildControls()
Controls.Add(ctlGloTinyControl)
End Sub

End Class
End Namespace

Namespace Controls
Public Class TinyControl
Inherits WebControl
Implements INamingContainer

Private hypGloLink As New HyperLink

Public Sub New()
hypGloLink.Text = "Let's go!"
hypGloLink.NavigateUrl = "http://www.google.com"
End Sub

Protected Overrides Sub CreateChildControls()
MyBase.CreateChildControls()
Controls.Add(hypGloLink)
End Sub

Public Overrides Sub Dispose()
HttpContext.Current.Response.Write("DISPOSING!")
MyBase.Dispose()
GC.SuppressFinalize(True)
End Sub

End Class
End Namespace


When you load the control with .NET MP as it is, if you do a snapshot you will see that MiniControl and it's child TinyControl (and containing HyperLink) are disposed correctly, and you will see "DISPOSED!" written to the page. However, if you uncomment the line of code marked for uncommenting, when you stop and run the application again and take a new snapshot, you will see that while MiniControl still disposes correctly, TinyControl (and it's HyperLink control) remains undisposed. "DISPOSED!" is also not written to the page output, showing that the child controls of MiniControl never have their Disposed() called. This will happen for any control contained in the now "invisible" MiniControl. Continually refreshing the page will show that the undisposed count of TinyControl and it's HyperLink will continue to rise indefinitely. What's going on here? How can we get invisible controls to dispose correctly? It seems silly that changing the visibility of a control would have any impact on it being disposed.

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Mon Mar 24, 2008 8:27 pm

If a Web control is not visible, there is no reason for the framework to create the child controls of the control, since neither the parent control nor the child controls will be rendered. So in your example, the MiniControl.CreateChildControls method will not be called if the MiniControl is not visible (and neither will the TinyControl.CreateChildControls method). The problem with the undisposed instances is that you create a new instance of both the TinyControl and the HyperLink, even if they will never be registered with the framework. A solution would be to lazily initialize the TinyControl and the HyperLink, e.g.:

Code: Select all

Namespace Controls
    Public Class Test
        Inherits WebControl
        Implements INamingContainer

        Private ctlGloMiniControl As MiniControl

        Protected Overrides Sub CreateChildControls()
            MyBase.CreateChildControls()
            ctlGloMiniControl = New MiniControl
            Controls.Add(ctlGloMiniControl)
            ' ctlGloMiniControl.Visible = False 'Uncomment me! 
        End Sub

    End Class
End Namespace

Namespace Controls
    Public Class MiniControl
        Inherits WebControl
        Implements INamingContainer

        Private ctlGloTinyControl As TinyControl

        Protected Overrides Sub CreateChildControls()
            MyBase.CreateChildControls()

            ctlGloTinyControl = New TinyControl
            Controls.Add(ctlGloTinyControl)
        End Sub

        Public Overrides Sub Dispose()
            MyBase.Dispose()
        End Sub

    End Class
End Namespace

Namespace Controls
    Public Class TinyControl
        Inherits WebControl
        Implements INamingContainer

        Private hypGloLink As HyperLink

        Public Sub New()
        End Sub

        Protected Overrides Sub CreateChildControls()
            MyBase.CreateChildControls()

            hypGloLink = New HyperLink
            hypGloLink.Text = "Let's go!"
            hypGloLink.NavigateUrl = "http://www.google.com"

            Controls.Add(hypGloLink)
        End Sub

        Public Overrides Sub Dispose()
            HttpContext.Current.Response.Write("DISPOSING!")
            MyBase.Dispose()
            GC.SuppressFinalize(True)
        End Sub

    End Class
End Namespace
Of course, since the child controls can now be unassigned, care has to be taken so that you don't get a NullReferenceException (e.g., the initalization of hypGloLink must be moved from "New" to "CreateChildControls").

Another option is to call Dispose on the child controls yourself, preferably after calling MyBase.Dispose.
Best regards,

Andreas Suurkuusk
SciTech Software AB

QScend
Posts: 8
Joined: Tue Mar 04, 2008 5:40 pm

Post by QScend » Tue Mar 25, 2008 3:27 pm

Yes, manually overriding and calling Dispose() on the child controls is what we've started doing and for the most part works, except for in a few cases where it's outside our reach to do so (we use Telerik's RadControls and even with a manual call, a few of their controls' children don't completely dispose). While I understand the lack of need to call CreateChildControls() on children that won't be displayed, it still seems wrong to me that Dispose() is never called, as some things initialized in New() may need cleaning up. We use a concept similar to Master Pages, which we wrote ourselves since we've been doing this since the 1.0 framework before Master Pages existed. Hence, we use a lot of controls that often have their visibility set to false. Regardless, now we know that .NET is not going to change so we have some code reworking to do. Thanks much for the input.

Post Reply

Who is online

Users browsing this forum: No registered users and 23 guests