Best Practice - Destroying objects

R

rowe_newsgroups

Setting fields to nothing can be extremely useful when dealing with
shared members. Since shared properties have an extremely long
lifetime compared to other objects (usually the length of the
application) set them to nothing can preserve memory.

Thanks,

Seth Rowe [MVP]
http://sethrowe.blogspot.com/
 
B

Bill McCarthy

rowe_newsgroups said:
Setting fields to nothing can be extremely useful when dealing with
shared members. Since shared properties have an extremely long
lifetime compared to other objects (usually the length of the
application) set them to nothing can preserve memory.

Thanks,

Huh ? Can you show me an example where that is the case ? Are you talking
about the type that exposes the Shared property, sure you could do that, but
in that case the Shared property would be returning multiple instances,
which could cause higher memory pressure in repeated calls.
For any consuming code, setting the instance to Nothing makes no difference
on a shared object: with the exception of WithEvents fields where you are
unwiring and hence releasing references to your consuming instance (aka a
circular reference where one node is Shared)
 
B

Brian Gideon

Huh ?  Can you show me an example where that is the case ?  Are you talking
about the type that exposes the Shared property, sure you could do that, but
in that case the Shared property would be returning multiple instances,
which could cause higher memory pressure in repeated calls.
For any consuming code, setting the instance to Nothing makes no difference
on a shared object: with the exception of WithEvents fields where you are
unwiring and hence releasing references to your consuming instance (aka a
circular reference where one node is Shared)

I think what Seth is trying to say can best expressed with the
following example.

Public Class A

Private m_Resource As Object = Nothing

Public Sub Open()
m_Resource = GetResource()
End Sub

Public Sub Close()
m_Resource = Nothing
End Sub

End Class

Since m_Resource is a field its reachability is dependent on the
lifetime of A. If we did not set m_Resource = Nothing in the Close
method its memory pressure would still be in play until A itself
became unreachable. This is a simple example demonstrating why
setting a field to Nothing can be useful. Notice that the field is
not even declared Shared.
 
B

Bill McCarthy

Hi Brian,


The example you gave was a private field beign set to nothing not a Shared Property. For a private field setting it to nothing has no impact unless you expect the containing class to stay around a lot longer. For example, consider this code:

Module Module1

Sub Main()
Dim a As New A
a.Open()

a = Nothing

Console.WriteLine("press enter to cause GC to collect")
Console.ReadLine()

GC.Collect()

Console.WriteLine("press enter to exit")
Console.ReadLine()
End Sub

End Module


Class A

Private _b As B = Nothing

Public Sub Open()
_b = New B
End Sub

Protected Overrides Sub Finalize()
Console.WriteLine("A finalized")
End Sub
End Class


Class B

Protected Overrides Sub Finalize()
Console.WriteLine("B finalized")
End Sub
End Class



You will see with the single call to Collect both Finalizers are called. So the GC collection catches all objects that are not referenced from a rootable object. When you think about it it has to do this to deal with circular references. The setting of the field to Nothing has no practical effect unless you are keeping the containing instance alive.

As to Shared properties, like I said previously you can't set them to nothing as then the behavior is no longer like they are shared and hence you shift the memory pressure to creating new instances. If containing types set their reference to Nothing a Shared property by nature will still be in memory until the appdomain is unloaded.
 
R

rowe_newsgroups

Hi Brian,


The example you gave was a private field beign set to nothing not a Shared Property.   For a private field setting it to nothing has no impact unless you expect the containing class to stay around a lot longer. For example, consider this code:

Module Module1

    Sub Main()
      Dim a As New A
      a.Open()

      a = Nothing

      Console.WriteLine("press enter to cause GC to collect")
      Console.ReadLine()

      GC.Collect()

      Console.WriteLine("press enter to exit")
      Console.ReadLine()
    End Sub

End Module

Class A

   Private _b As B = Nothing

   Public Sub Open()
      _b = New B
   End Sub

   Protected Overrides Sub Finalize()
      Console.WriteLine("A finalized")
   End Sub
End Class

Class B

   Protected Overrides Sub Finalize()
      Console.WriteLine("B finalized")
   End Sub
End Class

You will see with the single call to Collect both Finalizers are called.  So the GC collection catches all objects that are not referenced from a rootable object.  When you think about it it has to do this to deal with circular references. The setting of the field to Nothing has no practical effect unless you are keeping the containing instance alive.

As to Shared properties, like I said previously you can't set them to nothing as then the behavior is no longer like they are shared and hence you shift the memory pressure to creating new instances.  If containing types set their reference to Nothing a Shared property by nature will still be inmemory until the appdomain is unloaded.

This conversation details one of the reasons I dislike using Shared
properties. As I understand, the problem is that shared properties
aren't unreachable until the application ends, as at any time the
shared property could be referenced and the value would need to be
returned. The other problem is that you don't know (without making
dangerous assumptions about architecture and design) when a shared
property isn't going to be used anymore.

Consider the following:

///////////
Private Shared _MyDataSet As DataSet

Public Shared Property MyDataSet() As DataSet
Get
Return _MyDataSet
End Get
Set (value As DataSet)
_MyDataSet = value
End Set
End Property
///////////

Suppose at one part of the application, the MyDataSet is filled by a
query such as "Select * From tbl_BiggestTableInDatabase". For the rest
of the application's lifetime (this shared property won't go out of
scope) you have this massive dataset stored in memory. It would be
beneficial to set this to nothing and remove the dataset, but like I
said earlier, you can never be certain that you will know when the
property is not being used.

Thanks,

Seth Rowe [MVP]
http://sethrowe.blogspot.com/
 
B

Bill McCarthy

This conversation details one of the reasons I dislike using Shared
properties. As I understand, the problem is that shared properties
aren't unreachable until the application ends, as at any time the
shared property could be referenced and the value would need to be
returned. The other problem is that you don't know (without making
dangerous assumptions about architecture and design) when a shared
property isn't going to be used anymore.

Exactly. So you should generally not set shared properties to Nothing. You
should however consider carefully the design about having Shared properties
versus Shared functions
 
B

Brian Gideon

The setting of the field to Nothing has no practical effect unless you are keeping the containing instance alive.

That was my point. But, it works the same whether or not it is an
instance or shared field, except that the lifetime in the former is
dependent on the instance and later is dependent on the appdomain.
As to Shared properties, like I said previously you can't set them to nothing as then the behavior is no longer like they are shared and hence you shift the memory pressure to creating new instances.  If containing types set their reference to Nothing a Shared property by nature will still be inmemory until the appdomain is unloaded.

Hmm...I think I'm confused by the discussion of properties. If the
property takes the Nothing value and assigns it to shared reference
field then the object that was referenced by that field (assuming
there are no other references) will be eligible for collection
immediately. The result is that the memory allocated for the object
made available through the property could be reclaimed before the
appdomain ends. Obviously, I'm not understanding your point. Can you
explain a little more about what you mean?
 
R

rowe_newsgroups

Exactly.  So you should generally not set shared properties to Nothing. You
should however consider carefully the design about having Shared properties
versus Shared functions

My original comment was mainly aimed at the use of legacy code that
you have no control of. In many of those cases you may know when it is
safe to set the property to nothing and in that case it would be a
good idea.

This could be another good example for a class that implements
IDisposable. Suppose you must interact with a legacy code base that
makes (improper) use of shared properties. If your class fully
encapsulates the use of the legacy code through instance members, than
in the Dispose method you could safely set the legacy app's Shared
properties to nothing.

Thanks,

Seth Rowe [MVP]
http://sethrowe.blogspot.com/
 
B

Bill McCarthy

rowe_newsgroups said:
If your class fully
encapsulates the use of the legacy code through instance members, than
in the Dispose method you could safely set the legacy app's Shared
properties to nothing.


No, definitely not. Again, go back to the first sample I posted (brushes)
and see the issues that causes.
 
B

Bill McCarthy

Hmm...I think I'm confused by the discussion of properties. If the
property takes the Nothing value and assigns it to shared reference
field then the object that was referenced by that field (assuming
there are no other references) will be eligible for collection
immediately. The result is that the memory allocated for the object
made available through the property could be reclaimed before the
appdomain ends. Obviously, I'm not understanding your point. Can you
explain a little more about what you mean?

It no longer becomes shared. Again, look at the example around using shared
brushes. Or for another example, consider what happens with My.Forms.Form2
etc if you set that to Nothing : you force the disposing of the instance the
factory method exposes, hence closing that form regardless of what ever
other code thinks it had a valid reference. You cannot safely dispose
Shared resources as you don't know when there is no reference to them.
About the best you can do is expose the the property and use a WeakReference
as the backing field. That allows the GC to dispose of the resource (via
it's finalizer) if no other code is referencing it. If the reference is
still alive, you can pass on the target, if not re-instantiate. So again,
generally speaking you never set the actual resource to Nothing. Consuming
code can set their local references to Nothing, but never the actual Shared
resource or property.
 
B

Brian Gideon

It no longer becomes shared. Again, look at the example around using shared
brushes.  Or for another example, consider what happens with My.Forms.Form2
etc if you set that to Nothing : you force the disposing of the instance the
factory method exposes, hence closing that form regardless of what ever
other code thinks it had a valid reference.  You cannot safely dispose
Shared resources as you don't know when there is no reference to them.
About the best you can do is expose the the property and use a WeakReference
as the backing field. That allows the GC to dispose of the resource (via
it's finalizer) if no other code is referencing it.  If the reference is
still alive, you can pass on the target, if not re-instantiate.   So again,
generally speaking you never set the actual resource to Nothing. Consuming
code can set their local references to Nothing, but never the actual Shared
resource or property.

Okay, I'm totally with you now. Yes, you are exactly right. And I
see now why you were referring properties. If you make that resource
public (via a property or whatever) therein lies the problem. But, if
you keep that resource private then the containing class can make
better decisions on when to dispose it or set its field to nothing.
Again, I'm completely with you on that.
 
J

Jack Jackson

Hi Tim,



Use Using blocks, but use them with care. For example, let's say you have
this code in a form:

Using br As Brush = Brushes.CadetBlue
Me.CreateGraphics.DrawString("hello world", Me.Font, br, 50,
200)
End Using

Seems okay and works *once*. The problem with it is it calls dispose on a
Shared member.

That code doesn't dispose the Graphics object.
 
R

rowe_newsgroups

No, definitely not.  Again, go back to the first sample I posted (brushes)
and see the issues that causes.

Good point.

I guess the strategy would then be to open up Reflector, see what
exactly is being used where and why, wrap the sucker in some unit
tests, and then set the properties to nothing if deemed a necessary
risk. Depending on the application, it might be worth the risk to set
public properties to nothing to conserve memory usage (long running
applications). In any case, the code in question would need to be
aggressively tested to help ensure it wouldn't go "kaboom" when
shipped to prod.

Anyways, this has turned into a very interesting discussion!

:)

Thanks,

Seth Rowe [MVP]
http://sethrowe.blogspot.com/
 
H

Herfried K. Wagner [MVP]

Tim Marsden said:
Thanks for all the replies.

If I use the USING statement, do I still need to call the dispose method
before the END USING.

No.

The call of 'Dispose' is guaranteed when using 'Using...End Using' (the
'Dispose' call is placed in a 'Finally' branch of a 'Try...Catch' block
under the hoods). The only way to prevent the call of 'Dispose' in a
'Using' block is to kill the process.
 
B

Bill McCarthy

Jack Jackson said:
That code doesn't dispose the Graphics object.


Yes but that is not the issue I was demonstrating. The issue is the
disposing of the shared brush.
 

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

Similar Threads


Top